/* * 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. *
*/
static size_t cur_malloc_words = 0; // current size for MallocMaxTestWords
DEBUG_ONLY(bool os::_mutex_init_done = false;)
int os::snprintf(char* buf, size_t len, constchar* fmt, ...) {
va_list args;
va_start(args, fmt); int result = os::vsnprintf(buf, len, fmt, args);
va_end(args); return result;
}
// Fill in buffer with current local time as an ISO-8601 string. // E.g., YYYY-MM-DDThh:mm:ss.mmm+zzzz. // Returns buffer, or NULL if it failed. char* os::iso8601_time(char* buffer, size_t buffer_length, bool utc) { const jlong now = javaTimeMillis(); return os::iso8601_time(now, buffer, buffer_length, utc);
}
// Fill in buffer with an ISO-8601 string corresponding to the given javaTimeMillis value // E.g., yyyy-mm-ddThh:mm:ss-zzzz. // Returns buffer, or NULL if it failed. // This would mostly be a call to // strftime(...., "%Y-%m-%d" "T" "%H:%M:%S" "%z", ....) // except that on Windows the %z behaves badly, so we do it ourselves. // Also, people wanted milliseconds on there, // and strftime doesn't do milliseconds. char* os::iso8601_time(jlong milliseconds_since_19700101, char* buffer, size_t buffer_length, bool utc) { // Output will be of the form "YYYY-MM-DDThh:mm:ss.mmm+zzzz\0"
// Sanity check the arguments if (buffer == NULL) {
assert(false, "NULL buffer"); return NULL;
} if (buffer_length < os::iso8601_timestamp_size) {
assert(false, "buffer_length too small"); return NULL;
} constint milliseconds_per_microsecond = 1000; const time_t seconds_since_19700101 =
milliseconds_since_19700101 / milliseconds_per_microsecond; constint milliseconds_after_second =
milliseconds_since_19700101 % milliseconds_per_microsecond; // Convert the time value to a tm and timezone variable struct tm time_struct; if (utc) { if (gmtime_pd(&seconds_since_19700101, &time_struct) == NULL) {
assert(false, "Failed gmtime_pd"); return NULL;
}
} else { if (localtime_pd(&seconds_since_19700101, &time_struct) == NULL) {
assert(false, "Failed localtime_pd"); return NULL;
}
}
// No offset when dealing with UTC
time_t UTC_to_local = 0; if (!utc) { #ifdefined(_ALLBSD_SOURCE) || defined(_GNU_SOURCE)
UTC_to_local = -(time_struct.tm_gmtoff); #elifdefined(_WINDOWS) long zone;
_get_timezone(&zone);
UTC_to_local = static_cast<time_t>(zone); #else
UTC_to_local = timezone; #endif
// tm_gmtoff already includes adjustment for daylight saving #if !defined(_ALLBSD_SOURCE) && !defined(_GNU_SOURCE) // If daylight savings time is in effect, // we are 1 hour East of our time zone if (time_struct.tm_isdst > 0) {
UTC_to_local = UTC_to_local - seconds_per_hour;
} #endif
}
// Compute the time zone offset. // localtime_pd() sets timezone to the difference (in seconds) // between UTC and local time. // ISO 8601 says we need the difference between local time and UTC, // we change the sign of the localtime_pd() result. const time_t local_to_UTC = -(UTC_to_local); // Then we have to figure out if if we are ahead (+) or behind (-) UTC. char sign_local_to_UTC = '+';
time_t abs_local_to_UTC = local_to_UTC; if (local_to_UTC < 0) {
sign_local_to_UTC = '-';
abs_local_to_UTC = -(abs_local_to_UTC);
} // Convert time zone offset seconds to hours and minutes. const time_t zone_hours = (abs_local_to_UTC / seconds_per_hour); const time_t zone_min =
((abs_local_to_UTC % seconds_per_hour) / seconds_per_minute);
// Print an ISO 8601 date and time stamp into the buffer constint year = 1900 + time_struct.tm_year; constint month = 1 + time_struct.tm_mon; constint printed = jio_snprintf(buffer, buffer_length, "%04d-%02d-%02dT%02d:%02d:%02d.%03d%c%02d%02d",
year,
month,
time_struct.tm_mday,
time_struct.tm_hour,
time_struct.tm_min,
time_struct.tm_sec,
milliseconds_after_second,
sign_local_to_UTC,
zone_hours,
zone_min); if (printed == 0) {
assert(false, "Failed jio_printf"); return NULL;
} return buffer;
}
if ((p >= MinPriority && p <= MaxPriority) ||
(p == CriticalPriority && thread->is_ConcurrentGC_thread())) { int priority = java_to_os_priority[p]; return set_native_priority(thread, priority);
} else {
assert(false, "Should not happen"); return OS_ERR;
}
}
// The mapping from OS priority back to Java priority may be inexact because // Java priorities can map M:1 with native priorities. If you want the definite // Java priority then use JavaThread::java_priority()
OSReturn os::get_priority(const Thread* const thread, ThreadPriority& priority) { int p; int os_prio;
OSReturn ret = get_native_priority(thread, &os_prio); if (ret != OS_OK) return ret;
if (java_to_os_priority[MaxPriority] > java_to_os_priority[MinPriority]) { for (p = MaxPriority; p > MinPriority && java_to_os_priority[p] > os_prio; p--) ;
} else { // niceness values are in reverse order for (p = MaxPriority; p > MinPriority && java_to_os_priority[p] < os_prio; p--) ;
}
priority = (ThreadPriority)p; return OS_OK;
}
// Helper for dll_locate_lib. // Pass buffer and printbuffer as we already printed the path to buffer // when we called get_current_directory. This way we avoid another buffer // of size MAX_PATH. staticbool conc_path_file_and_check(char *buffer, char *printbuffer, size_t printbuflen, constchar* pname, char lastchar, constchar* fname) {
// Concatenate path and file name, but don't print double path separators. constchar *filesep = (WINDOWS_ONLY(lastchar == ':' ||) lastchar == os::file_separator()[0]) ? "" : os::file_separator(); int ret = jio_snprintf(printbuffer, printbuflen, "%s%s%s", pname, filesep, fname); // Check whether file exists. if (ret != -1) { struct stat statbuf; return os::stat(buffer, &statbuf) == 0;
} returnfalse;
}
// Frees all memory allocated on the heap for the // supplied array of arrays of chars (a), where n // is the number of elements in the array. staticvoid free_array_of_char_arrays(char** a, size_t n) { while (n > 0) {
n--; if (a[n] != NULL) {
FREE_C_HEAP_ARRAY(char, a[n]);
}
}
FREE_C_HEAP_ARRAY(char*, a);
}
// SIGBREAK is sent by the keyboard to query the VM state #ifndef SIGBREAK #define SIGBREAK SIGQUIT #endif
// sigexitnum_pd is a platform-specific special signal used for terminating the Signal thread.
staticvoid signal_thread_entry(JavaThread* thread, TRAPS) {
os::set_priority(thread, NearMaxPriority); while (true) { int sig;
{ // FIXME : Currently we have not decided what should be the status // for this java thread blocked here. Once we decide about // that we should fix this.
sig = os::signal_wait();
} if (sig == os::sigexitnum_pd()) { // Terminate the signal thread return;
}
switch (sig) { case SIGBREAK: { #if INCLUDE_SERVICES // Check if the signal is a trigger to start the Attach Listener - in that // case don't print stack traces. if (!DisableAttachMechanism) { // Attempt to transit state to AL_INITIALIZING.
AttachListenerState cur_state = AttachListener::transit_state(AL_INITIALIZING, AL_NOT_INITIALIZED); if (cur_state == AL_INITIALIZING) { // Attach Listener has been started to initialize. Ignore this signal. continue;
} elseif (cur_state == AL_NOT_INITIALIZED) { // Start to initialize. if (AttachListener::is_init_trigger()) { // Attach Listener has been initialized. // Accept subsequent request. continue;
} else { // Attach Listener could not be started. // So we need to transit the state to AL_NOT_INITIALIZED.
AttachListener::set_state(AL_NOT_INITIALIZED);
}
} elseif (AttachListener::check_socket_file()) { // Attach Listener has been started, but unix domain socket file // does not exist. So restart Attach Listener. continue;
}
} #endif // Print stack traces // Any SIGBREAK operations added here should make sure to flush // the output stream (e.g. tty->flush()) after output. See 4803766. // Each module also prints an extra carriage return after its output.
VM_PrintThreads op(tty, PrintConcurrentLocks, false/* no extended info */, true /* print JNI handle info */);
VMThread::execute(&op);
VM_FindDeadlocks op1(tty);
VMThread::execute(&op1);
Universe::print_heap_at_SIGBREAK(); if (PrintClassHistogram) {
VM_GC_HeapInspection op1(tty, true/* force full GC before heap inspection */);
VMThread::execute(&op1);
} if (JvmtiExport::should_post_data_dump()) {
JvmtiExport::post_data_dump();
} break;
} default: { // Dispatch the signal to java
HandleMark hm(THREAD);
Klass* klass = SystemDictionary::resolve_or_null(vmSymbols::jdk_internal_misc_Signal(), THREAD); if (klass != NULL) {
JavaValue result(T_VOID);
JavaCallArguments args;
args.push_int(sig);
JavaCalls::call_static(
&result,
klass,
vmSymbols::dispatch_name(),
vmSymbols::int_void_signature(),
&args,
THREAD
);
} if (HAS_PENDING_EXCEPTION) { // tty is initialized early so we don't expect it to be null, but // if it is we can't risk doing an initialization that might // trigger additional out-of-memory conditions if (tty != NULL) { char klass_name[256]; char tmp_sig_name[16]; constchar* sig_name = "UNKNOWN";
InstanceKlass::cast(PENDING_EXCEPTION->klass())->
name()->as_klass_external_name(klass_name, 256); if (os::exception_name(sig, tmp_sig_name, 16) != NULL)
sig_name = tmp_sig_name;
warning("Exception %s occurred dispatching signal %s to handler" "- the VM may need to be forcibly terminated",
klass_name, sig_name );
}
CLEAR_PENDING_EXCEPTION;
}
}
}
}
}
void os::init_before_ergo() {
initialize_initial_active_processor_count(); // We need to initialize large page support here because ergonomics takes some // decisions depending on large page support and the calculated large page size.
large_page_init();
StackOverflow::initialize_stack_zone_sizes();
// VM version initialization identifies some characteristics of the // platform that are used during ergonomic decisions.
VM_Version::init_before_ergo();
}
void os::initialize_jdk_signal_support(TRAPS) { if (!ReduceSignalUsage) { // Setup JavaThread for processing signals constchar* name = "Signal Dispatcher";
Handle thread_oop = JavaThread::create_system_thread_object(name, true/* visible */, CHECK);
JavaThread* thread = new JavaThread(&signal_thread_entry);
JavaThread::vm_exit_on_osthread_failure(thread);
// Load java dll if (dll_locate_lib(buffer, sizeof(buffer), Arguments::get_dll_dir(), "java")) {
_native_java_library = dll_load(buffer, ebuf, sizeof(ebuf));
} if (_native_java_library == NULL) {
vm_exit_during_initialization("Unable to load native library", ebuf);
}
#ifdefined(__OpenBSD__) // Work-around OpenBSD's lack of $ORIGIN support by pre-loading libnet.so // ignore errors if (dll_locate_lib(buffer, sizeof(buffer), Arguments::get_dll_dir(), "net")) {
dll_load(buffer, ebuf, sizeof(ebuf));
} #endif
} return _native_java_library;
}
/* * Support for finding Agent_On(Un)Load/Attach<_lib_name> if it exists. * If check_lib == true then we are looking for an * Agent_OnLoad_lib_name or Agent_OnAttach_lib_name function to determine if * this library is statically linked into the image. * If check_lib == false then we will look for the appropriate symbol in the * executable if agent_lib->is_static_lib() == true or in the shared library * referenced by 'handle'.
*/ void* os::find_agent_function(AgentLibrary *agent_lib, bool check_lib, constchar *syms[], size_t syms_len) {
assert(agent_lib != NULL, "sanity check"); constchar *lib_name; void *handle = agent_lib->os_lib(); void *entryName = NULL; char *agent_function_name;
size_t i;
// If checking then use the agent name otherwise test is_static_lib() to // see how to process this lookup
lib_name = ((check_lib || agent_lib->is_static_lib()) ? agent_lib->name() : NULL); for (i = 0; i < syms_len; i++) {
agent_function_name = build_agent_function_name(syms[i], lib_name, agent_lib->is_absolute_path()); if (agent_function_name == NULL) { break;
}
entryName = dll_lookup(handle, agent_function_name);
FREE_C_HEAP_ARRAY(char, agent_function_name); if (entryName != NULL) { break;
}
} return entryName;
}
// See if the passed in agent is statically linked into the VM image. bool os::find_builtin_agent(AgentLibrary *agent_lib, constchar *syms[],
size_t syms_len) { void *ret; void *proc_handle; void *save_handle;
assert(agent_lib != NULL, "sanity check"); if (agent_lib->name() == NULL) { returnfalse;
}
proc_handle = get_default_process_handle(); // Check for Agent_OnLoad/Attach_lib_name function
save_handle = agent_lib->os_lib(); // We want to look in this process' symbol table.
agent_lib->set_os_lib(proc_handle);
ret = find_agent_function(agent_lib, true, syms, syms_len); if (ret != NULL) { // Found an entry point like Agent_OnLoad_lib_name so we have a static agent
agent_lib->set_valid();
agent_lib->set_static_lib(true); returntrue;
}
agent_lib->set_os_lib(save_handle); returnfalse;
}
// Special handling for NMT preinit phase before arguments are parsed void* rc = NULL; if (NMTPreInit::handle_malloc(&rc, size)) { // No need to fill with 0 because DumpSharedSpaces doesn't use these // early allocations. return rc;
}
DEBUG_ONLY(check_crash_protection());
// On malloc(0), implementations of malloc(3) have the choice to return either // NULL or a unique non-NULL pointer. To unify libc behavior across our platforms // we chose the latter.
size = MAX2((size_t)1, size);
// For the test flag -XX:MallocMaxTestWords if (has_reached_max_malloc_test_peak(size)) { return NULL;
}
if (DumpSharedSpaces) { // Need to deterministically fill all the alignment gaps in C++ structures.
::memset(inner_ptr, 0, size);
} else {
DEBUG_ONLY(::memset(inner_ptr, uninitBlockPad, size);)
}
DEBUG_ONLY(break_if_ptr_caught(inner_ptr);) return inner_ptr;
}
// Special handling for NMT preinit phase before arguments are parsed void* rc = NULL; if (NMTPreInit::handle_realloc(&rc, memblock, size)) { return rc;
}
if (memblock == NULL) { return os::malloc(size, memflags, stack);
}
DEBUG_ONLY(check_crash_protection());
// On realloc(p, 0), implementers of realloc(3) have the choice to return either // NULL or a unique non-NULL pointer. To unify libc behavior across our platforms // we chose the latter.
size = MAX2((size_t)1, size);
// For the test flag -XX:MallocMaxTestWords if (has_reached_max_malloc_test_peak(size)) { return NULL;
}
if (MemTracker::enabled()) { // NMT realloc handling
// Perform integrity checks on and mark the old block as dead *before* calling the real realloc(3) since it // may invalidate the old block, including its header.
MallocHeader* header = MallocTracker::malloc_header(memblock);
header->assert_block_integrity(); // Assert block hasn't been tampered with. const MallocHeader::FreeInfo free_info = header->free_info();
header->mark_block_as_dead();
// the real realloc
ALLOW_C_FUNCTION(::realloc, void* const new_outer_ptr = ::realloc(header, new_outer_size);)
if (new_outer_ptr == NULL) { // realloc(3) failed and the block still exists. // We have however marked it as dead, revert this change.
header->revive(); return nullptr;
} // realloc(3) succeeded, variable header now points to invalid memory and we need to deaccount the old block.
MemTracker::deaccount(free_info);
// After a successful realloc(3), we account the resized block with its new size // to NMT. void* const new_inner_ptr = MemTracker::record_malloc(new_outer_ptr, size, memflags, stack);
#ifdef ASSERT
size_t old_size = free_info.size; if (old_size < size) { // We also zap the newly extended region.
::memset((char*)new_inner_ptr + old_size, uninitBlockPad, size - old_size);
} #endif
int os::next_random(unsignedint rand_seed) { /* standard, well-known linear congruential random generator with * next_rand = (16807*seed) mod (2**31-1) * see * (1) "Random Number Generators: Good Ones Are Hard to Find", * S.K. Park and K.W. Miller, Communications of the ACM 31:10 (Oct 1988), * (2) "Two Fast Implementations of the 'Minimal Standard' Random * Number Generator", David G. Carta, Comm. ACM 33, 1 (Jan 1990), pp. 87-88.
*/ constunsignedint a = 16807; constunsignedint m = 2147483647; constint q = m / a; assert(q == 127773, "weird math"); constint r = m % a; assert(r == 2836, "weird math");
// compute az=2^31p+q unsignedint lo = a * (rand_seed & 0xFFFF); unsignedint hi = a * (rand_seed >> 16);
lo += (hi & 0x7FFF) << 16;
// if q overflowed, ignore the overflow and increment q if (lo > m) {
lo &= m;
++lo;
}
lo += hi >> 15;
// if (p+q) overflowed, ignore the overflow and increment (p+q) if (lo > m) {
lo &= m;
++lo;
} return lo;
}
int os::random() { // Make updating the random seed thread safe. while (true) { unsignedint seed = _rand_seed; unsignedint rand = next_random(seed); if (Atomic::cmpxchg(&_rand_seed, seed, rand, memory_order_relaxed) == seed) { returnstatic_cast<int>(rand);
}
}
}
// The INITIALIZED state is distinguished from the SUSPENDED state because the // conditions in which a thread is first started are different from those in which // a suspension is resumed. These differences make it hard for us to apply the // tougher checks when starting threads that we want to do when resuming them. // However, when start_thread is called as a result of Thread.start, on a Java // thread, the operation is synchronized on the Java Thread object. So there // cannot be a race to start the thread and hence for the thread to exit while // we are working on it. Non-Java threads that start Java threads either have // to do so in a context in which races are impossible, or should do appropriate // locking.
//--------------------------------------------------------------------------- // Helper functions for fatal error handler
bool os::print_function_and_library_name(outputStream* st,
address addr, char* buf, int buflen, bool shorten_paths, bool demangle, bool strip_arguments) { // If no scratch buffer given, allocate one here on stack. // (used during error handling; its a coin toss, really, if on-stack allocation // is worse than (raw) C-heap allocation in that case). char* p = buf; if (p == NULL) {
p = (char*)::alloca(O_BUFLEN);
buflen = O_BUFLEN;
} int offset = 0; bool have_function_name = dll_address_to_function_name(addr, p, buflen,
&offset, demangle); bool is_function_descriptor = false; #ifdef HAVE_FUNCTION_DESCRIPTORS // When we deal with a function descriptor instead of a real code pointer, try to // resolve it. There is a small chance that a random pointer given to this function // may just happen to look like a valid descriptor, but this is rare and worth the // risk to see resolved function names. But we will print a little suffix to mark // this as a function descriptor for the reader (see below). if (!have_function_name && os::is_readable_pointer(addr)) {
address addr2 = (address)os::resolve_function_descriptor(addr); if (have_function_name = is_function_descriptor =
dll_address_to_function_name(addr2, p, buflen, &offset, demangle)) {
addr = addr2;
}
} #endif// HAVE_FUNCTION_DESCRIPTORS
if (have_function_name) { // Print function name, optionally demangled if (demangle && strip_arguments) { char* args_start = strchr(p, '('); if (args_start != NULL) {
*args_start = '\0';
}
} // Print offset. Omit printing if offset is zero, which makes the output // more readable if we print function pointers. if (offset == 0) {
st->print("%s", p);
} else {
st->print("%s+%d", p, offset);
}
} else {
st->print(PTR_FORMAT, p2i(addr));
}
offset = 0;
constbool have_library_name = dll_address_to_library_name(addr, p, buflen, &offset); if (have_library_name) { // Cut path parts if (shorten_paths) { char* p2 = strrchr(p, os::file_separator()[0]); if (p2 != NULL) {
p = p2 + 1;
}
}
st->print(" in %s", p); if (!have_function_name) { // Omit offset if we already printed the function offset
st->print("+%d", offset);
}
}
// Write a trailing marker if this was a function descriptor if (have_function_name && is_function_descriptor) {
st->print_raw(" (FD)");
}
for (int i = 0; env_list[i] != NULL; i++) { char *envvar = ::getenv(env_list[i]); if (envvar != NULL) {
st->print("%s", env_list[i]);
st->print("=");
st->print("%s", envvar); // Use separate cr() printing to avoid unnecessary buffer operations that might cause truncation.
st->cr();
}
}
}
}
void os::print_cpu_info(outputStream* st, char* buf, size_t buflen) { // cpu
st->print("CPU:"); #ifdefined(__APPLE__) && !defined(ZERO) if (VM_Version::is_cpu_emulated()) {
st->print(" (EMULATED)");
} #endif
st->print(" total %d", os::processor_count()); // It's not safe to query number of active processors after crash // st->print("(active %d)", os::active_processor_count()); but we can // print the initial number of active processors. // We access the raw value here because the assert in the accessor will // fail if the crash occurs before initialization of this value.
st->print(" (initial active %d)", _initial_active_processor_count);
st->print(" %s", VM_Version::features_string());
st->cr();
pd_print_cpu_info(st, buf, buflen);
}
// Print a one line string summarizing the cpu, number of cores, memory, and operating system version void os::print_summary_info(outputStream* st, char* buf, size_t buflen) {
st->print("Host: "); #ifndef PRODUCT if (get_host_name(buf, buflen)) {
st->print("%s, ", buf);
} #endif// PRODUCT
get_summary_cpu_info(buf, buflen);
st->print("%s, ", buf);
size_t mem = physical_memory()/G; if (mem == 0) { // for low memory systems
mem = physical_memory()/M;
st->print("%d cores, " SIZE_FORMAT "M, ", processor_count(), mem);
} else {
st->print("%d cores, " SIZE_FORMAT "G, ", processor_count(), mem);
}
get_summary_os_info(buf, buflen);
st->print_raw(buf);
st->cr();
}
double t = os::elapsedTime(); // NOTE: a crash using printf("%f",...) on Linux was historically noted here. int eltime = (int)t; // elapsed time in seconds int eltimeFraction = (int) ((t - eltime) * 1000000);
// print elapsed time in a human-readable format: int eldays = eltime / secs_per_day; int day_secs = eldays * secs_per_day; int elhours = (eltime - day_secs) / secs_per_hour; int hour_secs = elhours * secs_per_hour; int elmins = (eltime - day_secs - hour_secs) / secs_per_min; int minute_secs = elmins * secs_per_min; int elsecs = (eltime - day_secs - hour_secs - minute_secs);
st->print_cr(" elapsed time: %d.%06d seconds (%dd %dh %dm %ds)", eltime, eltimeFraction, eldays, elhours, elmins, elsecs);
}
// Check if pointer can be read from (4-byte read access). // Helps to prove validity of a not-NULL pointer. // Returns true in very early stages of VM life when stub is not yet generated. bool os::is_readable_pointer(constvoid* p) { int* const aligned = (int*) align_down((intptr_t)p, 4); int cafebabe = 0xcafebabe; // tester value 1 int deadbeef = 0xdeadbeef; // tester value 2 return (SafeFetch32(aligned, cafebabe) != cafebabe) || (SafeFetch32(aligned, deadbeef) != deadbeef);
}
bool os::is_readable_range(constvoid* from, constvoid* to) { if ((uintptr_t)from >= (uintptr_t)to) returnfalse; for (uintptr_t p = align_down((uintptr_t)from, min_page_size()); p < (uintptr_t)to; p += min_page_size()) { if (!is_readable_pointer((constvoid*)p)) { returnfalse;
}
} returntrue;
}
// moved from debug.cpp (used to be find()) but still called from there // The verbose parameter is only set by the debug code in one case void os::print_location(outputStream* st, intptr_t x, bool verbose) {
address addr = (address)x; // Handle NULL first, so later checks don't need to protect against it. if (addr == NULL) {
st->print_cr("0x0 is NULL"); return;
}
// Check if addr points into a code blob.
CodeBlob* b = CodeCache::find_blob(addr); if (b != NULL) {
b->dump_for_addr(addr, st, verbose); return;
}
// Check if addr points into Java heap. if (Universe::heap()->print_location(st, addr)) { return;
}
bool accessible = is_readable_pointer(addr);
// Check if addr is a JNI handle. if (align_down((intptr_t)addr, sizeof(intptr_t)) != 0 && accessible) { if (JNIHandles::is_global_handle((jobject) addr)) {
st->print_cr(INTPTR_FORMAT " is a global jni handle", p2i(addr)); return;
} if (JNIHandles::is_weak_global_handle((jobject) addr)) {
st->print_cr(INTPTR_FORMAT " is a weak global jni handle", p2i(addr)); return;
}
}
// Check if addr belongs to a Java thread. for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) { // If the addr is a java thread print information about that. if (addr == (address)thread) { if (verbose) {
thread->print_on(st);
} else {
st->print_cr(INTPTR_FORMAT " is a thread", p2i(addr));
} return;
} // If the addr is in the stack region for this thread then report that // and print thread info if (thread->is_in_full_stack(addr)) {
st->print_cr(INTPTR_FORMAT " is pointing into the stack for thread: "
INTPTR_FORMAT, p2i(addr), p2i(thread)); if (verbose) thread->print_on(st); return;
}
}
// Check if in metaspace and print types that have vptrs if (Metaspace::contains(addr)) { if (Klass::is_valid((Klass*)addr)) {
st->print_cr(INTPTR_FORMAT " is a pointer to class: ", p2i(addr));
((Klass*)addr)->print_on(st);
} elseif (Method::is_valid_method((const Method*)addr)) {
((Method*)addr)->print_value_on(st);
st->cr();
} else { // Use addr->print() from the debugger instead (not here)
st->print_cr(INTPTR_FORMAT " is pointing into metadata", p2i(addr));
} return;
}
// Compressed klass needs to be decoded first. #ifdef _LP64 if (UseCompressedClassPointers && ((uintptr_t)addr &~ (uintptr_t)max_juint) == 0) {
narrowKlass narrow_klass = (narrowKlass)(uintptr_t)addr;
Klass* k = CompressedKlassPointers::decode_raw(narrow_klass);
if (Klass::is_valid(k)) {
st->print_cr(UINT32_FORMAT " is a compressed pointer to class: " INTPTR_FORMAT, narrow_klass, p2i((HeapWord*)k));
k->print_on(st); return;
}
} #endif
// Try an OS specific find if (os::find(addr, st)) { return;
}
if (accessible) {
st->print(INTPTR_FORMAT " points into unknown readable memory:", p2i(addr)); if (is_aligned(addr, sizeof(intptr_t))) {
st->print(" " PTR_FORMAT " |", *(intptr_t*)addr);
} for (address p = addr; p < align_up(addr + 1, sizeof(intptr_t)); ++p) {
st->print(" %02x", *(u1*)p);
}
st->cr(); return;
}
st->print_cr(INTPTR_FORMAT " is an unknown value", p2i(addr));
}
// Looks like all platforms can use the same function to check if C // stack is walkable beyond current frame. // Returns true if this is not the case, i.e. the frame is possibly // the first C frame on the stack. bool os::is_first_C_frame(frame* fr) {
#ifdef _WINDOWS returntrue; // native stack isn't walkable on windows this way. #endif // Load up sp, fp, sender sp and sender fp, check for reasonable values. // Check usp first, because if that's bad the other accessors may fault // on some architectures. Ditto ufp second, etc.
if (is_pointer_bad(fr->sp())) returntrue;
uintptr_t ufp = (uintptr_t)fr->fp(); if (is_pointer_bad(fr->fp())) returntrue;
// stack grows downwards; if old_fp is below current fp or if the stack // frame is too large, either the stack is corrupted or fp is not saved // on stack (i.e. on x86, ebp may be used as general register). The stack // is not walkable beyond current frame. if (old_fp < ufp) returntrue; if (old_fp - ufp > 64 * K) returntrue;
// Scan the format string to determine the length of the actual // boot classpath, and handle platform dependencies as well. int formatted_path_len = 0; constchar* p; for (p = format_string; *p != 0; ++p) { if (*p == '%') formatted_path_len += home_len - 1;
++formatted_path_len;
}
// This function is a proxy to fopen, it tries to add a non standard flag ('e' or 'N') // that ensures automatic closing of the file on exec. If it can not find support in // the underlying c library, it will make an extra system call (fcntl) to ensure automatic // closing of the file on exec.
FILE* os::fopen(constchar* path, constchar* mode) { char modified_mode[20];
assert(strlen(mode) + 1 < sizeof(modified_mode), "mode chars plus one extra must fit in buffer");
sprintf(modified_mode, "%s" LINUX_ONLY("e") BSD_ONLY("e") WINDOWS_ONLY("N"), mode);
FILE* file = ::fopen(path, modified_mode);
#if !(defined LINUX || defined BSD || defined _WINDOWS) // assume fcntl FD_CLOEXEC support as a backup solution when 'e' or 'N' // is not supported as mode in fopen if (file != NULL) { int fd = fileno(file); if (fd != -1) { int fd_flags = fcntl(fd, F_GETFD); if (fd_flags != -1) {
fcntl(fd, F_SETFD, fd_flags | FD_CLOEXEC);
}
}
} #endif
return file;
}
bool os::set_boot_path(char fileSep, char pathSep) { constchar* home = Arguments::get_java_home(); int home_len = (int)strlen(home);
// Splits a path, based on its separator, the number of // elements is returned back in "elements". // file_name_length is used as a modifier for each path's // length when compared to JVM_MAXPATHLEN. So if you know // each returned path will have something appended when // in use, you can pass the length of that in // file_name_length, to ensure we detect if any path // exceeds the maximum path length once prepended onto // the sub-path/file name. // It is the callers responsibility to: // a> check the value of "elements", which may be 0. // b> ignore any empty path elements // c> free up the data. char** os::split_path(constchar* path, size_t* elements, size_t file_name_length) {
*elements = (size_t)0; if (path == NULL || strlen(path) == 0 || file_name_length == (size_t)NULL) { return NULL;
} constchar psepchar = *os::path_separator(); char* inpath = NEW_C_HEAP_ARRAY(char, strlen(path) + 1, mtInternal);
strcpy(inpath, path);
size_t count = 1; char* p = strchr(inpath, psepchar); // Get a count of elements to allocate memory while (p != NULL) {
count++;
p++;
p = strchr(p, psepchar);
}
// do the actual splitting
p = inpath; for (size_t i = 0 ; i < count ; i++) {
size_t len = strcspn(p, os::path_separator()); if (len + file_name_length > JVM_MAXPATHLEN) { // release allocated storage before exiting the vm
free_array_of_char_arrays(opath, i++);
vm_exit_during_initialization("The VM tried to use a path that exceeds the maximum path length for " "this system. Review path-containing parameters and properties, such as " "sun.boot.library.path, to identify potential sources for this path.");
} // allocate the string and add terminator storage char* s = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
strncpy(s, p, len);
s[len] = '\0';
opath[i] = s;
p += len + 1;
}
FREE_C_HEAP_ARRAY(char, inpath);
*elements = count; return opath;
}
// Returns true if the current stack pointer is above the stack shadow // pages, false otherwise. bool os::stack_shadow_pages_available(Thread *thread, const methodHandle& method, address sp) { if (!thread->is_Java_thread()) returnfalse; // Check if we have StackShadowPages above the guard zone. This parameter // is dependent on the depth of the maximum VM call stack possible from // the handler for stack overflow. 'instanceof' in the stack overflow // handler or a println uses at least 8k stack of VM and native code // respectively. constint framesize_in_bytes =
Interpreter::size_top_interpreter_activation(method()) * wordSize;
// The following enums are not defined on all platforms. #ifdef ESTALE
DEFINE_ENTRY(ESTALE, "Reserved") #endif #ifdef EDQUOT
DEFINE_ENTRY(EDQUOT, "Reserved") #endif #ifdef EMULTIHOP
DEFINE_ENTRY(EMULTIHOP, "Reserved") #endif
// End marker.
{ -1, "Unknown errno", "Unknown error" }
};
#undef DEFINE_ENTRY #undef ALL_FLAGS
int i = 0; while (table[i].v != -1 && table[i].v != e) {
i ++;
}
// This is the working definition of a server class machine: // >= 2 physical CPU's and >=2GB of memory, with some fuzz // because the graphics memory (?) sometimes masks physical memory. // If you want to change the definition of a server class machine // on some OS or platform, e.g., >=4GB on Windows platforms, // then you'll have to parameterize this method based on that state, // as was done for logical processors here, or replicate and // specialize this method for each platform. (Or fix os to have // some inheritance structure and use subclassing. Sigh.) // If you want some platform to always or never behave as a server // class machine, change the setting of AlwaysActAsServerClassMachine // and NeverActAsServerClassMachine in globals*.hpp. bool os::is_server_class_machine() { // First check for the early returns if (NeverActAsServerClassMachine) { returnfalse;
} if (AlwaysActAsServerClassMachine) { returntrue;
} // Then actually look at the machine bool result = false; constunsignedint server_processors = 2; const julong server_memory = 2UL * G; // We seem not to get our full complement of memory. // We allow some part (1/8?) of the memory to be "missing", // based on the sizes of DIMMs, and maybe graphics cards. const julong missing_memory = 256UL * M;
/* Is this a server class machine? */ if ((os::active_processor_count() >= (int)server_processors) &&
(os::physical_memory() >= (server_memory - missing_memory))) { constunsignedint logical_processors =
VM_Version::logical_processors_per_package(); if (logical_processors > 1) { constunsignedint physical_packages =
os::active_processor_count() / logical_processors; if (physical_packages >= server_processors) {
result = true;
}
} else {
result = true;
}
} return result;
}
void os::initialize_initial_active_processor_count() {
assert(_initial_active_processor_count == 0, "Initial active processor count already set.");
_initial_active_processor_count = active_processor_count();
log_debug(os)("Initial active processor count set to %d" , _initial_active_processor_count);
}
bool os::uncommit_memory(char* addr, size_t bytes, bool executable) {
assert_nonempty_range(addr, bytes); bool res; if (MemTracker::enabled()) {
Tracker tkr(Tracker::uncommit);
res = pd_uncommit_memory(addr, bytes, executable); if (res) {
tkr.record((address)addr, bytes);
}
} else {
res = pd_uncommit_memory(addr, bytes, executable);
} return res;
}
bool os::release_memory(char* addr, size_t bytes) {
assert_nonempty_range(addr, bytes); bool res; if (MemTracker::enabled()) { // Note: Tracker contains a ThreadCritical.
Tracker tkr(Tracker::release);
res = pd_release_memory(addr, bytes); if (res) {
tkr.record((address)addr, bytes);
}
} else {
res = pd_release_memory(addr, bytes);
} if (!res) {
log_info(os)("os::release_memory failed (" PTR_FORMAT ", " SIZE_FORMAT ")", p2i(addr), bytes);
} return res;
}
// Prints all mappings void os::print_memory_mappings(outputStream* st) {
os::print_memory_mappings(nullptr, (size_t)-1, st);
}
// Pretouching must use a store, not just a load. On many OSes loads from // fresh memory would be satisfied from a single mapped page containing all // zeros. We need to store something to each page to get them backed by // their own memory, which is the effect we want here. An atomic add of // zero is used instead of a simple store, allowing the memory to be used // while pretouch is in progress, rather than requiring users of the memory // to wait until the entire range has been touched. This is technically // a UB data race, but doesn't cause any problems for us. void os::pretouch_memory(void* start, void* end, size_t page_size) {
assert(start <= end, "invalid range: " PTR_FORMAT " -> " PTR_FORMAT, p2i(start), p2i(end));
assert(is_power_of_2(page_size), "page size misaligned: %zu", page_size);
assert(page_size >= sizeof(int), "page size too small: %zu", page_size); if (start < end) { // We're doing concurrent-safe touch and memory state has page // granularity, so we can touch anywhere in a page. Touch at the // beginning of each page to simplify iteration. char* cur = static_cast<char*>(align_down(start, page_size)); void* last = align_down(static_cast<char*>(end) - 1, page_size);
assert(cur <= last, "invariant"); // Iterate from first page through last (inclusive), being careful to // avoid overflow if the last page abuts the end of the address range. for ( ; true; cur += page_size) {
Atomic::add(reinterpret_cast<int*>(cur), 0, memory_order_relaxed); if (cur >= last) break;
}
}
}
char* os::map_memory_to_file(size_t bytes, int file_desc) { // Could have called pd_reserve_memory() followed by replace_existing_mapping_with_file_mapping(), // but AIX may use SHM in which case its more trouble to detach the segment and remap memory to the file. // On all current implementations NULL is interpreted as any available address. char* result = os::map_memory_to_file(NULL /* addr */, bytes, file_desc); if (result != NULL) {
MemTracker::record_virtual_memory_reserve_and_commit(result, bytes, CALLER_PC);
} return result;
}
char* os::attempt_map_memory_to_file_at(char* addr, size_t bytes, int file_desc) { char* result = pd_attempt_map_memory_to_file_at(addr, bytes, file_desc); if (result != NULL) {
MemTracker::record_virtual_memory_reserve_and_commit((address)result, bytes, CALLER_PC);
} return result;
}
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.