/* * Copyright (c) 1997, 2020, 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. * */ #ifndef SHARE_RUNTIME_OS_HPP #define SHARE_RUNTIME_OS_HPP #include "jvm.h" #include "jvmtifiles/jvmti.h" #include "metaprogramming/integralConstant.hpp" #include "utilities/exceptions.hpp" #include "utilities/ostream.hpp" #include "utilities/macros.hpp" #ifndef _WINDOWS # include #endif #ifdef __APPLE__ # include #endif class AgentLibrary; class frame; // os defines the interface to operating system; this includes traditional // OS services (time, I/O) as well as other functionality with system- // dependent code. class Thread; class JavaThread; class NativeCallStack; class methodHandle; class OSThread; class Mutex; template class GrowableArray; // %%%%% Moved ThreadState, START_FN, OSThread to new osThread.hpp. -- Rose // Platform-independent error return values from OS functions enum OSReturn { OS_OK = 0, // Operation was successful OS_ERR = -1, // Operation failed OS_INTRPT = -2, // Operation was interrupted OS_TIMEOUT = -3, // Operation timed out OS_NOMEM = -5, // Operation failed for lack of memory OS_NORESOURCE = -6 // Operation failed for lack of nonmemory resource }; enum ThreadPriority { // JLS 20.20.1-3 NoPriority = -1, // Initial non-priority value MinPriority = 1, // Minimum priority NormPriority = 5, // Normal (non-daemon) priority NearMaxPriority = 9, // High priority, used for VMThread MaxPriority = 10, // Highest priority, used for WatcherThread // ensures that VMThread doesn't starve profiler CriticalPriority = 11 // Critical thread priority }; // Executable parameter flag for os::commit_memory() and // os::commit_memory_or_exit(). const bool ExecMem = true; // Typedef for structured exception handling support typedef void (*java_call_t)(JavaValue* value, const methodHandle& method, JavaCallArguments* args, Thread* thread); class MallocTracker; class os: AllStatic { friend class VMStructs; friend class JVMCIVMStructs; friend class MallocTracker; #ifdef ASSERT private: static bool _mutex_init_done; public: static void set_mutex_init_done() { _mutex_init_done = true; } static bool mutex_init_done() { return _mutex_init_done; } #endif public: enum { page_sizes_max = 9 }; // Size of _page_sizes array (8 plus a sentinel) private: static OSThread* _starting_thread; static address _polling_page; public: static size_t _page_sizes[page_sizes_max]; private: static void init_page_sizes(size_t default_page_size) { _page_sizes[0] = default_page_size; _page_sizes[1] = 0; // sentinel } static char* pd_reserve_memory(size_t bytes, char* addr = 0, size_t alignment_hint = 0, bool executable = false); static char* pd_attempt_reserve_memory_at(size_t bytes, char* addr); static char* pd_attempt_reserve_memory_at(size_t bytes, char* addr, int file_desc); static bool pd_commit_memory(char* addr, size_t bytes, bool executable); static bool pd_commit_memory(char* addr, size_t size, size_t alignment_hint, bool executable); // Same as pd_commit_memory() that either succeeds or calls // vm_exit_out_of_memory() with the specified mesg. static void pd_commit_memory_or_exit(char* addr, size_t bytes, bool executable, const char* mesg); static void pd_commit_memory_or_exit(char* addr, size_t size, size_t alignment_hint, bool executable, const char* mesg); static bool pd_uncommit_memory(char* addr, size_t bytes, bool exec); static bool pd_release_memory(char* addr, size_t bytes); static char* pd_map_memory(int fd, const char* file_name, size_t file_offset, char *addr, size_t bytes, bool read_only = false, bool allow_exec = false); static char* pd_remap_memory(int fd, const char* file_name, size_t file_offset, char *addr, size_t bytes, bool read_only, bool allow_exec); static bool pd_unmap_memory(char *addr, size_t bytes); static void pd_free_memory(char *addr, size_t bytes, size_t alignment_hint); static void pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint); static char* pd_reserve_memory_special(size_t size, size_t alignment, char* addr, bool executable); static bool pd_release_memory_special(char* addr, size_t bytes); static size_t page_size_for_region(size_t region_size, size_t min_pages, bool must_be_aligned); // Get summary strings for system information in buffer provided static void get_summary_cpu_info(char* buf, size_t buflen); static void get_summary_os_info(char* buf, size_t buflen); static void initialize_initial_active_processor_count(); LINUX_ONLY(static void pd_init_container_support();) public: static void init(void); // Called before command line parsing static void init_container_support() { // Called during command line parsing. LINUX_ONLY(pd_init_container_support();) } static void init_before_ergo(void); // Called after command line parsing // before VM ergonomics processing. static jint init_2(void); // Called after command line parsing // and VM ergonomics processing // unset environment variable static bool unsetenv(const char* name); static bool have_special_privileges(); static jlong javaTimeMillis(); static jlong javaTimeNanos(); static void javaTimeNanos_info(jvmtiTimerInfo *info_ptr); static void javaTimeSystemUTC(jlong &seconds, jlong &nanos); static void run_periodic_checks(); static bool supports_monotonic_clock(); // Returns the elapsed time in seconds since the vm started. static double elapsedTime(); // Returns real time in seconds since an arbitrary point // in the past. static bool getTimesSecs(double* process_real_time, double* process_user_time, double* process_system_time); // Interface to the performance counter static jlong elapsed_counter(); static jlong elapsed_frequency(); // The "virtual time" of a thread is the amount of time a thread has // actually run. The first function indicates whether the OS supports // this functionality for the current thread, and if so the second // returns the elapsed virtual time for the current thread. static bool supports_vtime(); static double elapsedVTime(); // Return current local time in a string (YYYY-MM-DD HH:MM:SS). // It is MT safe, but not async-safe, as reading time zone // information may require a lock on some platforms. static char* local_time_string(char *buf, size_t buflen); static struct tm* localtime_pd (const time_t* clock, struct tm* res); static struct tm* gmtime_pd (const time_t* clock, struct tm* res); // 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. static char* iso8601_time(char* buffer, size_t buffer_length, bool utc = false); // Interface for detecting multiprocessor system static inline bool is_MP() { // During bootstrap if _processor_count is not yet initialized // we claim to be MP as that is safest. If any platform has a // stub generator that might be triggered in this phase and for // which being declared MP when in fact not, is a problem - then // the bootstrap routine for the stub generator needs to check // the processor count directly and leave the bootstrap routine // in place until called after initialization has ocurred. return (_processor_count != 1); } static julong available_memory(); static julong physical_memory(); static bool has_allocatable_memory_limit(julong* limit); static bool is_server_class_machine(); // Returns the id of the processor on which the calling thread is currently executing. // The returned value is guaranteed to be between 0 and (os::processor_count() - 1). static uint processor_id(); // number of CPUs static int processor_count() { return _processor_count; } static void set_processor_count(int count) { _processor_count = count; } // Returns the number of CPUs this process is currently allowed to run on. // Note that on some OSes this can change dynamically. static int active_processor_count(); // At startup the number of active CPUs this process is allowed to run on. // This value does not change dynamically. May be different from active_processor_count(). static int initial_active_processor_count() { assert(_initial_active_processor_count > 0, "Initial active processor count not set yet."); return _initial_active_processor_count; } // Binds the current process to a processor. // Returns true if it worked, false if it didn't. static bool bind_to_processor(uint processor_id); // Give a name to the current thread. static void set_native_thread_name(const char *name); // Interface for stack banging (predetect possible stack overflow for // exception processing) There are guard pages, and above that shadow // pages for stack overflow checking. static bool uses_stack_guard_pages(); static bool must_commit_stack_guard_pages(); static void map_stack_shadow_pages(address sp); static bool stack_shadow_pages_available(Thread *thread, const methodHandle& method, address sp); // Find committed memory region within specified range (start, start + size), // return true if found any static bool committed_in_range(address start, size_t size, address& committed_start, size_t& committed_size); // OS interface to Virtual Memory // Return the default page size. static int vm_page_size(); // Returns the page size to use for a region of memory. // region_size / min_pages will always be greater than or equal to the // returned value. The returned value will divide region_size. static size_t page_size_for_region_aligned(size_t region_size, size_t min_pages); // Returns the page size to use for a region of memory. // region_size / min_pages will always be greater than or equal to the // returned value. The returned value might not divide region_size. static size_t page_size_for_region_unaligned(size_t region_size, size_t min_pages); // Return the largest page size that can be used static size_t max_page_size() { // The _page_sizes array is sorted in descending order. return _page_sizes[0]; } // Return a lower bound for page sizes. Also works before os::init completed. static size_t min_page_size() { return 4 * K; } // Methods for tracing page sizes returned by the above method. // The region_{min,max}_size parameters should be the values // passed to page_size_for_region() and page_size should be the result of that // call. The (optional) base and size parameters should come from the // ReservedSpace base() and size() methods. static void trace_page_sizes(const char* str, const size_t* page_sizes, int count); static void trace_page_sizes(const char* str, const size_t region_min_size, const size_t region_max_size, const size_t page_size, const char* base, const size_t size); static void trace_page_sizes_for_requested_size(const char* str, const size_t requested_size, const size_t page_size, const size_t alignment, const char* base, const size_t size); static int vm_allocation_granularity(); static char* reserve_memory(size_t bytes, char* addr = 0, size_t alignment_hint = 0, int file_desc = -1, bool executable = false); static char* reserve_memory(size_t bytes, char* addr, size_t alignment_hint, MEMFLAGS flags); static char* reserve_memory_aligned(size_t size, size_t alignment, int file_desc = -1); static char* attempt_reserve_memory_at(size_t bytes, char* addr, int file_desc = -1); // Split a reserved memory region [base, base+size) into two regions [base, base+split) and // [base+split, base+size). // This may remove the original mapping, so its content may be lost. // Both base and split point must be aligned to allocation granularity; split point shall // be >0 and function name // which is used to find statically linked in agents. static char* build_agent_function_name(const char *sym, const char *cname, bool is_absolute_path); class SuspendedThreadTaskContext { public: SuspendedThreadTaskContext(Thread* thread, void *ucontext) : _thread(thread), _ucontext(ucontext) {} Thread* thread() const { return _thread; } void* ucontext() const { return _ucontext; } private: Thread* _thread; void* _ucontext; }; class SuspendedThreadTask { public: SuspendedThreadTask(Thread* thread) : _thread(thread), _done(false) {} void run(); bool is_done() { return _done; } virtual void do_task(const SuspendedThreadTaskContext& context) = 0; protected: ~SuspendedThreadTask() {} private: void internal_do_task(); Thread* _thread; bool _done; }; #ifndef _WINDOWS // Suspend/resume support // Protocol: // // a thread starts in SR_RUNNING // // SR_RUNNING can go to // * SR_SUSPEND_REQUEST when the WatcherThread wants to suspend it // SR_SUSPEND_REQUEST can go to // * SR_RUNNING if WatcherThread decides it waited for SR_SUSPENDED too long (timeout) // * SR_SUSPENDED if the stopped thread receives the signal and switches state // SR_SUSPENDED can go to // * SR_WAKEUP_REQUEST when the WatcherThread has done the work and wants to resume // SR_WAKEUP_REQUEST can go to // * SR_RUNNING when the stopped thread receives the signal // * SR_WAKEUP_REQUEST on timeout (resend the signal and try again) class SuspendResume { public: enum State { SR_RUNNING, SR_SUSPEND_REQUEST, SR_SUSPENDED, SR_WAKEUP_REQUEST }; private: volatile State _state; private: /* try to switch state from state "from" to state "to" * returns the state set after the method is complete */ State switch_state(State from, State to); public: SuspendResume() : _state(SR_RUNNING) { } State state() const { return _state; } State request_suspend() { return switch_state(SR_RUNNING, SR_SUSPEND_REQUEST); } State cancel_suspend() { return switch_state(SR_SUSPEND_REQUEST, SR_RUNNING); } State suspended() { return switch_state(SR_SUSPEND_REQUEST, SR_SUSPENDED); } State request_wakeup() { return switch_state(SR_SUSPENDED, SR_WAKEUP_REQUEST); } State running() { return switch_state(SR_WAKEUP_REQUEST, SR_RUNNING); } bool is_running() const { return _state == SR_RUNNING; } bool is_suspended() const { return _state == SR_SUSPENDED; } }; #endif // !WINDOWS protected: static volatile unsigned int _rand_seed; // seed for random number generator static int _processor_count; // number of processors static int _initial_active_processor_count; // number of active processors during initialization. static char* format_boot_path(const char* format_string, const char* home, int home_len, char fileSep, char pathSep); static bool set_boot_path(char fileSep, char pathSep); }; // Note that "PAUSE" is almost always used with synchronization // so arguably we should provide Atomic::SpinPause() instead // of the global SpinPause() with C linkage. // It'd also be eligible for inlining on many platforms. extern "C" int SpinPause(); #endif // SHARE_RUNTIME_OS_HPP