| duke@0 | /*
|
| trims@1772 | * Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved.
|
| duke@0 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
| duke@0 | *
|
| duke@0 | * This code is free software; you can redistribute it and/or modify it
|
| duke@0 | * under the terms of the GNU General Public License version 2 only, as
|
| duke@0 | * published by the Free Software Foundation.
|
| duke@0 | *
|
| duke@0 | * This code is distributed in the hope that it will be useful, but WITHOUT
|
| duke@0 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
| duke@0 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
| duke@0 | * version 2 for more details (a copy is included in the LICENSE file that
|
| duke@0 | * accompanied this code).
|
| duke@0 | *
|
| duke@0 | * You should have received a copy of the GNU General Public License version
|
| duke@0 | * 2 along with this work; if not, write to the Free Software Foundation,
|
| duke@0 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
| duke@0 | *
|
| trims@1772 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
| trims@1772 | * or visit www.oracle.com if you need additional information or have any
|
| trims@1772 | * questions.
|
| duke@0 | *
|
| duke@0 | */
|
| coleenp@1621 |
|
| coleenp@1621 | # define __STDC_FORMAT_MACROS
|
| duke@0 |
|
| duke@0 | // do not include precompiled header file
|
| duke@0 | # include "incls/_os_linux.cpp.incl"
|
| duke@0 |
|
| duke@0 | // put OS-includes here
|
| duke@0 | # include <sys/types.h>
|
| duke@0 | # include <sys/mman.h>
|
| bobv@1892 | # include <sys/stat.h>
|
| bobv@1892 | # include <sys/select.h>
|
| duke@0 | # include <pthread.h>
|
| duke@0 | # include <signal.h>
|
| duke@0 | # include <errno.h>
|
| duke@0 | # include <dlfcn.h>
|
| duke@0 | # include <stdio.h>
|
| duke@0 | # include <unistd.h>
|
| duke@0 | # include <sys/resource.h>
|
| duke@0 | # include <pthread.h>
|
| duke@0 | # include <sys/stat.h>
|
| duke@0 | # include <sys/time.h>
|
| duke@0 | # include <sys/times.h>
|
| duke@0 | # include <sys/utsname.h>
|
| duke@0 | # include <sys/socket.h>
|
| duke@0 | # include <sys/wait.h>
|
| duke@0 | # include <pwd.h>
|
| duke@0 | # include <poll.h>
|
| duke@0 | # include <semaphore.h>
|
| duke@0 | # include <fcntl.h>
|
| duke@0 | # include <string.h>
|
| duke@0 | # include <syscall.h>
|
| duke@0 | # include <sys/sysinfo.h>
|
| duke@0 | # include <gnu/libc-version.h>
|
| duke@0 | # include <sys/ipc.h>
|
| duke@0 | # include <sys/shm.h>
|
| duke@0 | # include <link.h>
|
| coleenp@1621 | # include <stdint.h>
|
| coleenp@1621 | # include <inttypes.h>
|
| duke@0 |
|
| duke@0 | #define MAX_PATH (2 * K)
|
| duke@0 |
|
| duke@0 | // for timer info max values which include all bits
|
| duke@0 | #define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF)
|
| duke@0 | #define SEC_IN_NANOSECS 1000000000LL
|
| duke@0 |
|
| duke@0 | ////////////////////////////////////////////////////////////////////////////////
|
| duke@0 | // global variables
|
| duke@0 | julong os::Linux::_physical_memory = 0;
|
| duke@0 |
|
| duke@0 | address os::Linux::_initial_thread_stack_bottom = NULL;
|
| duke@0 | uintptr_t os::Linux::_initial_thread_stack_size = 0;
|
| duke@0 |
|
| duke@0 | int (*os::Linux::_clock_gettime)(clockid_t, struct timespec *) = NULL;
|
| duke@0 | int (*os::Linux::_pthread_getcpuclockid)(pthread_t, clockid_t *) = NULL;
|
| duke@0 | Mutex* os::Linux::_createThread_lock = NULL;
|
| duke@0 | pthread_t os::Linux::_main_thread;
|
| duke@0 | int os::Linux::_page_size = -1;
|
| duke@0 | bool os::Linux::_is_floating_stack = false;
|
| duke@0 | bool os::Linux::_is_NPTL = false;
|
| duke@0 | bool os::Linux::_supports_fast_thread_cpu_time = false;
|
| xlu@254 | const char * os::Linux::_glibc_version = NULL;
|
| xlu@254 | const char * os::Linux::_libpthread_version = NULL;
|
| duke@0 |
|
| duke@0 | static jlong initial_time_count=0;
|
| duke@0 |
|
| duke@0 | static int clock_tics_per_sec = 100;
|
| duke@0 |
|
| duke@0 | // For diagnostics to print a message once. see run_periodic_checks
|
| duke@0 | static sigset_t check_signal_done;
|
| duke@0 | static bool check_signals = true;;
|
| duke@0 |
|
| duke@0 | static pid_t _initial_pid = 0;
|
| duke@0 |
|
| duke@0 | /* Signal number used to suspend/resume a thread */
|
| duke@0 |
|
| duke@0 | /* do not use any signal number less than SIGSEGV, see 4355769 */
|
| duke@0 | static int SR_signum = SIGUSR2;
|
| duke@0 | sigset_t SR_sigset;
|
| kamg@299 |
|
| kamg@299 | /* Used to protect dlsym() calls */
|
| kamg@299 | static pthread_mutex_t dl_mutex;
|
| duke@0 |
|
| duke@0 | ////////////////////////////////////////////////////////////////////////////////
|
| duke@0 | // utility functions
|
| duke@0 |
|
| duke@0 | static int SR_initialize();
|
| duke@0 | static int SR_finalize();
|
| duke@0 |
|
| duke@0 | julong os::available_memory() {
|
| duke@0 | return Linux::available_memory();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | julong os::Linux::available_memory() {
|
| duke@0 | // values in struct sysinfo are "unsigned long"
|
| duke@0 | struct sysinfo si;
|
| duke@0 | sysinfo(&si);
|
| duke@0 |
|
| duke@0 | return (julong)si.freeram * si.mem_unit;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | julong os::physical_memory() {
|
| duke@0 | return Linux::physical_memory();
|
| phh@78 | }
|
| phh@78 |
|
| phh@78 | julong os::allocatable_physical_memory(julong size) {
|
| phh@78 | #ifdef _LP64
|
| phh@78 | return size;
|
| phh@78 | #else
|
| phh@78 | julong result = MIN2(size, (julong)3800*M);
|
| phh@78 | if (!is_allocatable(result)) {
|
| phh@78 | // See comments under solaris for alignment considerations
|
| phh@78 | julong reasonable_size = (julong)2*G - 2 * os::vm_page_size();
|
| phh@78 | result = MIN2(size, reasonable_size);
|
| phh@78 | }
|
| phh@78 | return result;
|
| phh@78 | #endif // _LP64
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | ////////////////////////////////////////////////////////////////////////////////
|
| duke@0 | // environment support
|
| duke@0 |
|
| duke@0 | bool os::getenv(const char* name, char* buf, int len) {
|
| duke@0 | const char* val = ::getenv(name);
|
| duke@0 | if (val != NULL && strlen(val) < (size_t)len) {
|
| duke@0 | strcpy(buf, val);
|
| duke@0 | return true;
|
| duke@0 | }
|
| duke@0 | if (len > 0) buf[0] = 0; // return a null string
|
| duke@0 | return false;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 |
|
| duke@0 | // Return true if user is running as root.
|
| duke@0 |
|
| duke@0 | bool os::have_special_privileges() {
|
| duke@0 | static bool init = false;
|
| duke@0 | static bool privileges = false;
|
| duke@0 | if (!init) {
|
| duke@0 | privileges = (getuid() != geteuid()) || (getgid() != getegid());
|
| duke@0 | init = true;
|
| duke@0 | }
|
| duke@0 | return privileges;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 |
|
| duke@0 | #ifndef SYS_gettid
|
| duke@0 | // i386: 224, ia64: 1105, amd64: 186, sparc 143
|
| duke@0 | #ifdef __ia64__
|
| duke@0 | #define SYS_gettid 1105
|
| duke@0 | #elif __i386__
|
| duke@0 | #define SYS_gettid 224
|
| duke@0 | #elif __amd64__
|
| duke@0 | #define SYS_gettid 186
|
| duke@0 | #elif __sparc__
|
| duke@0 | #define SYS_gettid 143
|
| duke@0 | #else
|
| duke@0 | #error define gettid for the arch
|
| duke@0 | #endif
|
| duke@0 | #endif
|
| duke@0 |
|
| duke@0 | // Cpu architecture string
|
| never@1241 | #if defined(ZERO)
|
| never@1241 | static char cpu_arch[] = ZERO_LIBARCH;
|
| never@1241 | #elif defined(IA64)
|
| duke@0 | static char cpu_arch[] = "ia64";
|
| duke@0 | #elif defined(IA32)
|
| duke@0 | static char cpu_arch[] = "i386";
|
| duke@0 | #elif defined(AMD64)
|
| duke@0 | static char cpu_arch[] = "amd64";
|
| bobv@1892 | #elif defined(ARM)
|
| bobv@1892 | static char cpu_arch[] = "arm";
|
| bobv@1892 | #elif defined(PPC)
|
| bobv@1892 | static char cpu_arch[] = "ppc";
|
| duke@0 | #elif defined(SPARC)
|
| duke@0 | # ifdef _LP64
|
| duke@0 | static char cpu_arch[] = "sparcv9";
|
| duke@0 | # else
|
| duke@0 | static char cpu_arch[] = "sparc";
|
| duke@0 | # endif
|
| duke@0 | #else
|
| duke@0 | #error Add appropriate cpu_arch setting
|
| duke@0 | #endif
|
| duke@0 |
|
| duke@0 |
|
| duke@0 | // pid_t gettid()
|
| duke@0 | //
|
| duke@0 | // Returns the kernel thread id of the currently running thread. Kernel
|
| duke@0 | // thread id is used to access /proc.
|
| duke@0 | //
|
| duke@0 | // (Note that getpid() on LinuxThreads returns kernel thread id too; but
|
| duke@0 | // on NPTL, it returns the same pid for all threads, as required by POSIX.)
|
| duke@0 | //
|
| duke@0 | pid_t os::Linux::gettid() {
|
| duke@0 | int rslt = syscall(SYS_gettid);
|
| duke@0 | if (rslt == -1) {
|
| duke@0 | // old kernel, no NPTL support
|
| duke@0 | return getpid();
|
| duke@0 | } else {
|
| duke@0 | return (pid_t)rslt;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Most versions of linux have a bug where the number of processors are
|
| duke@0 | // determined by looking at the /proc file system. In a chroot environment,
|
| duke@0 | // the system call returns 1. This causes the VM to act as if it is
|
| duke@0 | // a single processor and elide locking (see is_MP() call).
|
| duke@0 | static bool unsafe_chroot_detected = false;
|
| xlu@254 | static const char *unstable_chroot_error = "/proc file system not found.\n"
|
| xlu@254 | "Java may be unstable running multithreaded in a chroot "
|
| xlu@254 | "environment on Linux when /proc filesystem is not mounted.";
|
| duke@0 |
|
| duke@0 | void os::Linux::initialize_system_info() {
|
| phh@1352 | set_processor_count(sysconf(_SC_NPROCESSORS_CONF));
|
| phh@1352 | if (processor_count() == 1) {
|
| duke@0 | pid_t pid = os::Linux::gettid();
|
| duke@0 | char fname[32];
|
| duke@0 | jio_snprintf(fname, sizeof(fname), "/proc/%d", pid);
|
| duke@0 | FILE *fp = fopen(fname, "r");
|
| duke@0 | if (fp == NULL) {
|
| duke@0 | unsafe_chroot_detected = true;
|
| duke@0 | } else {
|
| duke@0 | fclose(fp);
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | _physical_memory = (julong)sysconf(_SC_PHYS_PAGES) * (julong)sysconf(_SC_PAGESIZE);
|
| phh@1352 | assert(processor_count() > 0, "linux error");
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | void os::init_system_properties_values() {
|
| duke@0 | // char arch[12];
|
| duke@0 | // sysinfo(SI_ARCHITECTURE, arch, sizeof(arch));
|
| duke@0 |
|
| duke@0 | // The next steps are taken in the product version:
|
| duke@0 | //
|
| duke@0 | // Obtain the JAVA_HOME value from the location of libjvm[_g].so.
|
| duke@0 | // This library should be located at:
|
| duke@0 | // <JAVA_HOME>/jre/lib/<arch>/{client|server}/libjvm[_g].so.
|
| duke@0 | //
|
| duke@0 | // If "/jre/lib/" appears at the right place in the path, then we
|
| duke@0 | // assume libjvm[_g].so is installed in a JDK and we use this path.
|
| duke@0 | //
|
| duke@0 | // Otherwise exit with message: "Could not create the Java virtual machine."
|
| duke@0 | //
|
| duke@0 | // The following extra steps are taken in the debugging version:
|
| duke@0 | //
|
| duke@0 | // If "/jre/lib/" does NOT appear at the right place in the path
|
| duke@0 | // instead of exit check for $JAVA_HOME environment variable.
|
| duke@0 | //
|
| duke@0 | // If it is defined and we are able to locate $JAVA_HOME/jre/lib/<arch>,
|
| duke@0 | // then we append a fake suffix "hotspot/libjvm[_g].so" to this path so
|
| duke@0 | // it looks like libjvm[_g].so is installed there
|
| duke@0 | // <JAVA_HOME>/jre/lib/<arch>/hotspot/libjvm[_g].so.
|
| duke@0 | //
|
| duke@0 | // Otherwise exit.
|
| duke@0 | //
|
| duke@0 | // Important note: if the location of libjvm.so changes this
|
| duke@0 | // code needs to be changed accordingly.
|
| duke@0 |
|
| duke@0 | // The next few definitions allow the code to be verbatim:
|
| duke@0 | #define malloc(n) (char*)NEW_C_HEAP_ARRAY(char, (n))
|
| duke@0 | #define getenv(n) ::getenv(n)
|
| duke@0 |
|
| duke@0 | /*
|
| duke@0 | * See ld(1):
|
| duke@0 | * The linker uses the following search paths to locate required
|
| duke@0 | * shared libraries:
|
| duke@0 | * 1: ...
|
| duke@0 | * ...
|
| duke@0 | * 7: The default directories, normally /lib and /usr/lib.
|
| duke@0 | */
|
| kvn@639 | #if defined(AMD64) || defined(_LP64) && (defined(SPARC) || defined(PPC) || defined(S390))
|
| kvn@639 | #define DEFAULT_LIBPATH "/usr/lib64:/lib64:/lib:/usr/lib"
|
| kvn@639 | #else
|
| duke@0 | #define DEFAULT_LIBPATH "/lib:/usr/lib"
|
| kvn@639 | #endif
|
| duke@0 |
|
| duke@0 | #define EXTENSIONS_DIR "/lib/ext"
|
| duke@0 | #define ENDORSED_DIR "/lib/endorsed"
|
| duke@0 | #define REG_DIR "/usr/java/packages"
|
| duke@0 |
|
| duke@0 | {
|
| duke@0 | /* sysclasspath, java_home, dll_dir */
|
| duke@0 | {
|
| duke@0 | char *home_path;
|
| duke@0 | char *dll_path;
|
| duke@0 | char *pslash;
|
| duke@0 | char buf[MAXPATHLEN];
|
| duke@0 | os::jvm_path(buf, sizeof(buf));
|
| duke@0 |
|
| duke@0 | // Found the full path to libjvm.so.
|
| duke@0 | // Now cut the path to <java_home>/jre if we can.
|
| duke@0 | *(strrchr(buf, '/')) = '\0'; /* get rid of /libjvm.so */
|
| duke@0 | pslash = strrchr(buf, '/');
|
| duke@0 | if (pslash != NULL)
|
| duke@0 | *pslash = '\0'; /* get rid of /{client|server|hotspot} */
|
| duke@0 | dll_path = malloc(strlen(buf) + 1);
|
| duke@0 | if (dll_path == NULL)
|
| duke@0 | return;
|
| duke@0 | strcpy(dll_path, buf);
|
| duke@0 | Arguments::set_dll_dir(dll_path);
|
| duke@0 |
|
| duke@0 | if (pslash != NULL) {
|
| duke@0 | pslash = strrchr(buf, '/');
|
| duke@0 | if (pslash != NULL) {
|
| duke@0 | *pslash = '\0'; /* get rid of /<arch> */
|
| duke@0 | pslash = strrchr(buf, '/');
|
| duke@0 | if (pslash != NULL)
|
| duke@0 | *pslash = '\0'; /* get rid of /lib */
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | home_path = malloc(strlen(buf) + 1);
|
| duke@0 | if (home_path == NULL)
|
| duke@0 | return;
|
| duke@0 | strcpy(home_path, buf);
|
| duke@0 | Arguments::set_java_home(home_path);
|
| duke@0 |
|
| duke@0 | if (!set_boot_path('/', ':'))
|
| duke@0 | return;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | /*
|
| duke@0 | * Where to look for native libraries
|
| duke@0 | *
|
| duke@0 | * Note: Due to a legacy implementation, most of the library path
|
| duke@0 | * is set in the launcher. This was to accomodate linking restrictions
|
| duke@0 | * on legacy Linux implementations (which are no longer supported).
|
| duke@0 | * Eventually, all the library path setting will be done here.
|
| duke@0 | *
|
| duke@0 | * However, to prevent the proliferation of improperly built native
|
| duke@0 | * libraries, the new path component /usr/java/packages is added here.
|
| duke@0 | * Eventually, all the library path setting will be done here.
|
| duke@0 | */
|
| duke@0 | {
|
| duke@0 | char *ld_library_path;
|
| duke@0 |
|
| duke@0 | /*
|
| duke@0 | * Construct the invariant part of ld_library_path. Note that the
|
| duke@0 | * space for the colon and the trailing null are provided by the
|
| duke@0 | * nulls included by the sizeof operator (so actually we allocate
|
| duke@0 | * a byte more than necessary).
|
| duke@0 | */
|
| duke@0 | ld_library_path = (char *) malloc(sizeof(REG_DIR) + sizeof("/lib/") +
|
| duke@0 | strlen(cpu_arch) + sizeof(DEFAULT_LIBPATH));
|
| duke@0 | sprintf(ld_library_path, REG_DIR "/lib/%s:" DEFAULT_LIBPATH, cpu_arch);
|
| duke@0 |
|
| duke@0 | /*
|
| duke@0 | * Get the user setting of LD_LIBRARY_PATH, and prepended it. It
|
| duke@0 | * should always exist (until the legacy problem cited above is
|
| duke@0 | * addressed).
|
| duke@0 | */
|
| duke@0 | char *v = getenv("LD_LIBRARY_PATH");
|
| duke@0 | if (v != NULL) {
|
| duke@0 | char *t = ld_library_path;
|
| duke@0 | /* That's +1 for the colon and +1 for the trailing '\0' */
|
| duke@0 | ld_library_path = (char *) malloc(strlen(v) + 1 + strlen(t) + 1);
|
| duke@0 | sprintf(ld_library_path, "%s:%s", v, t);
|
| duke@0 | }
|
| duke@0 | Arguments::set_library_path(ld_library_path);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | /*
|
| duke@0 | * Extensions directories.
|
| duke@0 | *
|
| duke@0 | * Note that the space for the colon and the trailing null are provided
|
| duke@0 | * by the nulls included by the sizeof operator (so actually one byte more
|
| duke@0 | * than necessary is allocated).
|
| duke@0 | */
|
| duke@0 | {
|
| duke@0 | char *buf = malloc(strlen(Arguments::get_java_home()) +
|
| duke@0 | sizeof(EXTENSIONS_DIR) + sizeof(REG_DIR) + sizeof(EXTENSIONS_DIR));
|
| duke@0 | sprintf(buf, "%s" EXTENSIONS_DIR ":" REG_DIR EXTENSIONS_DIR,
|
| duke@0 | Arguments::get_java_home());
|
| duke@0 | Arguments::set_ext_dirs(buf);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | /* Endorsed standards default directory. */
|
| duke@0 | {
|
| duke@0 | char * buf;
|
| duke@0 | buf = malloc(strlen(Arguments::get_java_home()) + sizeof(ENDORSED_DIR));
|
| duke@0 | sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home());
|
| duke@0 | Arguments::set_endorsed_dirs(buf);
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | #undef malloc
|
| duke@0 | #undef getenv
|
| duke@0 | #undef EXTENSIONS_DIR
|
| duke@0 | #undef ENDORSED_DIR
|
| duke@0 |
|
| duke@0 | // Done
|
| duke@0 | return;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | ////////////////////////////////////////////////////////////////////////////////
|
| duke@0 | // breakpoint support
|
| duke@0 |
|
| duke@0 | void os::breakpoint() {
|
| duke@0 | BREAKPOINT;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | extern "C" void breakpoint() {
|
| duke@0 | // use debugger to set breakpoint here
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | ////////////////////////////////////////////////////////////////////////////////
|
| duke@0 | // signal support
|
| duke@0 |
|
| duke@0 | debug_only(static bool signal_sets_initialized = false);
|
| duke@0 | static sigset_t unblocked_sigs, vm_sigs, allowdebug_blocked_sigs;
|
| duke@0 |
|
| duke@0 | bool os::Linux::is_sig_ignored(int sig) {
|
| duke@0 | struct sigaction oact;
|
| duke@0 | sigaction(sig, (struct sigaction*)NULL, &oact);
|
| duke@0 | void* ohlr = oact.sa_sigaction ? CAST_FROM_FN_PTR(void*, oact.sa_sigaction)
|
| duke@0 | : CAST_FROM_FN_PTR(void*, oact.sa_handler);
|
| duke@0 | if (ohlr == CAST_FROM_FN_PTR(void*, SIG_IGN))
|
| duke@0 | return true;
|
| duke@0 | else
|
| duke@0 | return false;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | void os::Linux::signal_sets_init() {
|
| duke@0 | // Should also have an assertion stating we are still single-threaded.
|
| duke@0 | assert(!signal_sets_initialized, "Already initialized");
|
| duke@0 | // Fill in signals that are necessarily unblocked for all threads in
|
| duke@0 | // the VM. Currently, we unblock the following signals:
|
| duke@0 | // SHUTDOWN{1,2,3}_SIGNAL: for shutdown hooks support (unless over-ridden
|
| duke@0 | // by -Xrs (=ReduceSignalUsage));
|
| duke@0 | // BREAK_SIGNAL which is unblocked only by the VM thread and blocked by all
|
| duke@0 | // other threads. The "ReduceSignalUsage" boolean tells us not to alter
|
| duke@0 | // the dispositions or masks wrt these signals.
|
| duke@0 | // Programs embedding the VM that want to use the above signals for their
|
| duke@0 | // own purposes must, at this time, use the "-Xrs" option to prevent
|
| duke@0 | // interference with shutdown hooks and BREAK_SIGNAL thread dumping.
|
| duke@0 | // (See bug 4345157, and other related bugs).
|
| duke@0 | // In reality, though, unblocking these signals is really a nop, since
|
| duke@0 | // these signals are not blocked by default.
|
| duke@0 | sigemptyset(&unblocked_sigs);
|
| duke@0 | sigemptyset(&allowdebug_blocked_sigs);
|
| duke@0 | sigaddset(&unblocked_sigs, SIGILL);
|
| duke@0 | sigaddset(&unblocked_sigs, SIGSEGV);
|
| duke@0 | sigaddset(&unblocked_sigs, SIGBUS);
|
| duke@0 | sigaddset(&unblocked_sigs, SIGFPE);
|
| duke@0 | sigaddset(&unblocked_sigs, SR_signum);
|
| duke@0 |
|
| duke@0 | if (!ReduceSignalUsage) {
|
| duke@0 | if (!os::Linux::is_sig_ignored(SHUTDOWN1_SIGNAL)) {
|
| duke@0 | sigaddset(&unblocked_sigs, SHUTDOWN1_SIGNAL);
|
| duke@0 | sigaddset(&allowdebug_blocked_sigs, SHUTDOWN1_SIGNAL);
|
| duke@0 | }
|
| duke@0 | if (!os::Linux::is_sig_ignored(SHUTDOWN2_SIGNAL)) {
|
| duke@0 | sigaddset(&unblocked_sigs, SHUTDOWN2_SIGNAL);
|
| duke@0 | sigaddset(&allowdebug_blocked_sigs, SHUTDOWN2_SIGNAL);
|
| duke@0 | }
|
| duke@0 | if (!os::Linux::is_sig_ignored(SHUTDOWN3_SIGNAL)) {
|
| duke@0 | sigaddset(&unblocked_sigs, SHUTDOWN3_SIGNAL);
|
| duke@0 | sigaddset(&allowdebug_blocked_sigs, SHUTDOWN3_SIGNAL);
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | // Fill in signals that are blocked by all but the VM thread.
|
| duke@0 | sigemptyset(&vm_sigs);
|
| duke@0 | if (!ReduceSignalUsage)
|
| duke@0 | sigaddset(&vm_sigs, BREAK_SIGNAL);
|
| duke@0 | debug_only(signal_sets_initialized = true);
|
| duke@0 |
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // These are signals that are unblocked while a thread is running Java.
|
| duke@0 | // (For some reason, they get blocked by default.)
|
| duke@0 | sigset_t* os::Linux::unblocked_signals() {
|
| duke@0 | assert(signal_sets_initialized, "Not initialized");
|
| duke@0 | return &unblocked_sigs;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // These are the signals that are blocked while a (non-VM) thread is
|
| duke@0 | // running Java. Only the VM thread handles these signals.
|
| duke@0 | sigset_t* os::Linux::vm_signals() {
|
| duke@0 | assert(signal_sets_initialized, "Not initialized");
|
| duke@0 | return &vm_sigs;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // These are signals that are blocked during cond_wait to allow debugger in
|
| duke@0 | sigset_t* os::Linux::allowdebug_blocked_signals() {
|
| duke@0 | assert(signal_sets_initialized, "Not initialized");
|
| duke@0 | return &allowdebug_blocked_sigs;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | void os::Linux::hotspot_sigmask(Thread* thread) {
|
| duke@0 |
|
| duke@0 | //Save caller's signal mask before setting VM signal mask
|
| duke@0 | sigset_t caller_sigmask;
|
| duke@0 | pthread_sigmask(SIG_BLOCK, NULL, &caller_sigmask);
|
| duke@0 |
|
| duke@0 | OSThread* osthread = thread->osthread();
|
| duke@0 | osthread->set_caller_sigmask(caller_sigmask);
|
| duke@0 |
|
| duke@0 | pthread_sigmask(SIG_UNBLOCK, os::Linux::unblocked_signals(), NULL);
|
| duke@0 |
|
| duke@0 | if (!ReduceSignalUsage) {
|
| duke@0 | if (thread->is_VM_thread()) {
|
| duke@0 | // Only the VM thread handles BREAK_SIGNAL ...
|
| duke@0 | pthread_sigmask(SIG_UNBLOCK, vm_signals(), NULL);
|
| duke@0 | } else {
|
| duke@0 | // ... all other threads block BREAK_SIGNAL
|
| duke@0 | pthread_sigmask(SIG_BLOCK, vm_signals(), NULL);
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | //////////////////////////////////////////////////////////////////////////////
|
| duke@0 | // detecting pthread library
|
| duke@0 |
|
| duke@0 | void os::Linux::libpthread_init() {
|
| duke@0 | // Save glibc and pthread version strings. Note that _CS_GNU_LIBC_VERSION
|
| duke@0 | // and _CS_GNU_LIBPTHREAD_VERSION are supported in glibc >= 2.3.2. Use a
|
| duke@0 | // generic name for earlier versions.
|
| duke@0 | // Define macros here so we can build HotSpot on old systems.
|
| duke@0 | # ifndef _CS_GNU_LIBC_VERSION
|
| duke@0 | # define _CS_GNU_LIBC_VERSION 2
|
| duke@0 | # endif
|
| duke@0 | # ifndef _CS_GNU_LIBPTHREAD_VERSION
|
| duke@0 | # define _CS_GNU_LIBPTHREAD_VERSION 3
|
| duke@0 | # endif
|
| duke@0 |
|
| duke@0 | size_t n = confstr(_CS_GNU_LIBC_VERSION, NULL, 0);
|
| duke@0 | if (n > 0) {
|
| duke@0 | char *str = (char *)malloc(n);
|
| duke@0 | confstr(_CS_GNU_LIBC_VERSION, str, n);
|
| duke@0 | os::Linux::set_glibc_version(str);
|
| duke@0 | } else {
|
| duke@0 | // _CS_GNU_LIBC_VERSION is not supported, try gnu_get_libc_version()
|
| duke@0 | static char _gnu_libc_version[32];
|
| duke@0 | jio_snprintf(_gnu_libc_version, sizeof(_gnu_libc_version),
|
| duke@0 | "glibc %s %s", gnu_get_libc_version(), gnu_get_libc_release());
|
| duke@0 | os::Linux::set_glibc_version(_gnu_libc_version);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | n = confstr(_CS_GNU_LIBPTHREAD_VERSION, NULL, 0);
|
| duke@0 | if (n > 0) {
|
| duke@0 | char *str = (char *)malloc(n);
|
| duke@0 | confstr(_CS_GNU_LIBPTHREAD_VERSION, str, n);
|
| duke@0 | // Vanilla RH-9 (glibc 2.3.2) has a bug that confstr() always tells
|
| duke@0 | // us "NPTL-0.29" even we are running with LinuxThreads. Check if this
|
| xlu@254 | // is the case. LinuxThreads has a hard limit on max number of threads.
|
| xlu@254 | // So sysconf(_SC_THREAD_THREADS_MAX) will return a positive value.
|
| xlu@254 | // On the other hand, NPTL does not have such a limit, sysconf()
|
| xlu@254 | // will return -1 and errno is not changed. Check if it is really NPTL.
|
| duke@0 | if (strcmp(os::Linux::glibc_version(), "glibc 2.3.2") == 0 &&
|
| xlu@254 | strstr(str, "NPTL") &&
|
| xlu@254 | sysconf(_SC_THREAD_THREADS_MAX) > 0) {
|
| xlu@254 | free(str);
|
| xlu@254 | os::Linux::set_libpthread_version("linuxthreads");
|
| xlu@254 | } else {
|
| xlu@254 | os::Linux::set_libpthread_version(str);
|
| duke@0 | }
|
| duke@0 | } else {
|
| xlu@254 | // glibc before 2.3.2 only has LinuxThreads.
|
| xlu@254 | os::Linux::set_libpthread_version("linuxthreads");
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | if (strstr(libpthread_version(), "NPTL")) {
|
| ohair@20 | os::Linux::set_is_NPTL();
|
| duke@0 | } else {
|
| ohair@20 | os::Linux::set_is_LinuxThreads();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // LinuxThreads have two flavors: floating-stack mode, which allows variable
|
| duke@0 | // stack size; and fixed-stack mode. NPTL is always floating-stack.
|
| duke@0 | if (os::Linux::is_NPTL() || os::Linux::supports_variable_stack_size()) {
|
| ohair@20 | os::Linux::set_is_floating_stack();
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | /////////////////////////////////////////////////////////////////////////////
|
| duke@0 | // thread stack
|
| duke@0 |
|
| duke@0 | // Force Linux kernel to expand current thread stack. If "bottom" is close
|
| duke@0 | // to the stack guard, caller should block all signals.
|
| duke@0 | //
|
| duke@0 | // MAP_GROWSDOWN:
|
| duke@0 | // A special mmap() flag that is used to implement thread stacks. It tells
|
| duke@0 | // kernel that the memory region should extend downwards when needed. This
|
| duke@0 | // allows early versions of LinuxThreads to only mmap the first few pages
|
| duke@0 | // when creating a new thread. Linux kernel will automatically expand thread
|
| duke@0 | // stack as needed (on page faults).
|
| duke@0 | //
|
| duke@0 | // However, because the memory region of a MAP_GROWSDOWN stack can grow on
|
| duke@0 | // demand, if a page fault happens outside an already mapped MAP_GROWSDOWN
|
| duke@0 | // region, it's hard to tell if the fault is due to a legitimate stack
|
| duke@0 | // access or because of reading/writing non-exist memory (e.g. buffer
|
| duke@0 | // overrun). As a rule, if the fault happens below current stack pointer,
|
| duke@0 | // Linux kernel does not expand stack, instead a SIGSEGV is sent to the
|
| duke@0 | // application (see Linux kernel fault.c).
|
| duke@0 | //
|
| duke@0 | // This Linux feature can cause SIGSEGV when VM bangs thread stack for
|
| duke@0 | // stack overflow detection.
|
| duke@0 | //
|
| duke@0 | // Newer version of LinuxThreads (since glibc-2.2, or, RH-7.x) and NPTL do
|
| duke@0 | // not use this flag. However, the stack of initial thread is not created
|
| duke@0 | // by pthread, it is still MAP_GROWSDOWN. Also it's possible (though
|
| duke@0 | // unlikely) that user code can create a thread with MAP_GROWSDOWN stack
|
| duke@0 | // and then attach the thread to JVM.
|
| duke@0 | //
|
| duke@0 | // To get around the problem and allow stack banging on Linux, we need to
|
| duke@0 | // manually expand thread stack after receiving the SIGSEGV.
|
| duke@0 | //
|
| duke@0 | // There are two ways to expand thread stack to address "bottom", we used
|
| duke@0 | // both of them in JVM before 1.5:
|
| duke@0 | // 1. adjust stack pointer first so that it is below "bottom", and then
|
| duke@0 | // touch "bottom"
|
| duke@0 | // 2. mmap() the page in question
|
| duke@0 | //
|
| duke@0 | // Now alternate signal stack is gone, it's harder to use 2. For instance,
|
| duke@0 | // if current sp is already near the lower end of page 101, and we need to
|
| duke@0 | // call mmap() to map page 100, it is possible that part of the mmap() frame
|
| duke@0 | // will be placed in page 100. When page 100 is mapped, it is zero-filled.
|
| duke@0 | // That will destroy the mmap() frame and cause VM to crash.
|
| duke@0 | //
|
| duke@0 | // The following code works by adjusting sp first, then accessing the "bottom"
|
| duke@0 | // page to force a page fault. Linux kernel will then automatically expand the
|
| duke@0 | // stack mapping.
|
| duke@0 | //
|
| duke@0 | // _expand_stack_to() assumes its frame size is less than page size, which
|
| duke@0 | // should always be true if the function is not inlined.
|
| duke@0 |
|
| duke@0 | #if __GNUC__ < 3 // gcc 2.x does not support noinline attribute
|
| duke@0 | #define NOINLINE
|
| duke@0 | #else
|
| duke@0 | #define NOINLINE __attribute__ ((noinline))
|
| duke@0 | #endif
|
| duke@0 |
|
| duke@0 | static void _expand_stack_to(address bottom) NOINLINE;
|
| duke@0 |
|
| duke@0 | static void _expand_stack_to(address bottom) {
|
| duke@0 | address sp;
|
| duke@0 | size_t size;
|
| duke@0 | volatile char *p;
|
| duke@0 |
|
| duke@0 | // Adjust bottom to point to the largest address within the same page, it
|
| duke@0 | // gives us a one-page buffer if alloca() allocates slightly more memory.
|
| duke@0 | bottom = (address)align_size_down((uintptr_t)bottom, os::Linux::page_size());
|
| duke@0 | bottom += os::Linux::page_size() - 1;
|
| duke@0 |
|
| duke@0 | // sp might be slightly above current stack pointer; if that's the case, we
|
| duke@0 | // will alloca() a little more space than necessary, which is OK. Don't use
|
| duke@0 | // os::current_stack_pointer(), as its result can be slightly below current
|
| duke@0 | // stack pointer, causing us to not alloca enough to reach "bottom".
|
| duke@0 | sp = (address)&sp;
|
| duke@0 |
|
| duke@0 | if (sp > bottom) {
|
| duke@0 | size = sp - bottom;
|
| duke@0 | p = (volatile char *)alloca(size);
|
| duke@0 | assert(p != NULL && p <= (volatile char *)bottom, "alloca problem?");
|
| duke@0 | p[0] = '\0';
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | bool os::Linux::manually_expand_stack(JavaThread * t, address addr) {
|
| duke@0 | assert(t!=NULL, "just checking");
|
| duke@0 | assert(t->osthread()->expanding_stack(), "expand should be set");
|
| duke@0 | assert(t->stack_base() != NULL, "stack_base was not initialized");
|
| duke@0 |
|
| duke@0 | if (addr < t->stack_base() && addr >= t->stack_yellow_zone_base()) {
|
| duke@0 | sigset_t mask_all, old_sigset;
|
| duke@0 | sigfillset(&mask_all);
|
| duke@0 | pthread_sigmask(SIG_SETMASK, &mask_all, &old_sigset);
|
| duke@0 | _expand_stack_to(addr);
|
| duke@0 | pthread_sigmask(SIG_SETMASK, &old_sigset, NULL);
|
| duke@0 | return true;
|
| duke@0 | }
|
| duke@0 | return false;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | //////////////////////////////////////////////////////////////////////////////
|
| duke@0 | // create new thread
|
| duke@0 |
|
| duke@0 | static address highest_vm_reserved_address();
|
| duke@0 |
|
| duke@0 | // check if it's safe to start a new thread
|
| duke@0 | static bool _thread_safety_check(Thread* thread) {
|
| duke@0 | if (os::Linux::is_LinuxThreads() && !os::Linux::is_floating_stack()) {
|
| duke@0 | // Fixed stack LinuxThreads (SuSE Linux/x86, and some versions of Redhat)
|
| duke@0 | // Heap is mmap'ed at lower end of memory space. Thread stacks are
|
| duke@0 | // allocated (MAP_FIXED) from high address space. Every thread stack
|
| duke@0 | // occupies a fixed size slot (usually 2Mbytes, but user can change
|
| duke@0 | // it to other values if they rebuild LinuxThreads).
|
| duke@0 | //
|
| duke@0 | // Problem with MAP_FIXED is that mmap() can still succeed even part of
|
| duke@0 | // the memory region has already been mmap'ed. That means if we have too
|
| duke@0 | // many threads and/or very large heap, eventually thread stack will
|
| duke@0 | // collide with heap.
|
| duke@0 | //
|
| duke@0 | // Here we try to prevent heap/stack collision by comparing current
|
| duke@0 | // stack bottom with the highest address that has been mmap'ed by JVM
|
| duke@0 | // plus a safety margin for memory maps created by native code.
|
| duke@0 | //
|
| duke@0 | // This feature can be disabled by setting ThreadSafetyMargin to 0
|
| duke@0 | //
|
| duke@0 | if (ThreadSafetyMargin > 0) {
|
| duke@0 | address stack_bottom = os::current_stack_base() - os::current_stack_size();
|
| duke@0 |
|
| duke@0 | // not safe if our stack extends below the safety margin
|
| duke@0 | return stack_bottom - ThreadSafetyMargin >= highest_vm_reserved_address();
|
| duke@0 | } else {
|
| duke@0 | return true;
|
| duke@0 | }
|
| duke@0 | } else {
|
| duke@0 | // Floating stack LinuxThreads or NPTL:
|
| duke@0 | // Unlike fixed stack LinuxThreads, thread stacks are not MAP_FIXED. When
|
| duke@0 | // there's not enough space left, pthread_create() will fail. If we come
|
| duke@0 | // here, that means enough space has been reserved for stack.
|
| duke@0 | return true;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Thread start routine for all newly created threads
|
| duke@0 | static void *java_start(Thread *thread) {
|
| duke@0 | // Try to randomize the cache line index of hot stack frames.
|
| duke@0 | // This helps when threads of the same stack traces evict each other's
|
| duke@0 | // cache lines. The threads can be either from the same JVM instance, or
|
| duke@0 | // from different JVM instances. The benefit is especially true for
|
| duke@0 | // processors with hyperthreading technology.
|
| duke@0 | static int counter = 0;
|
| duke@0 | int pid = os::current_process_id();
|
| duke@0 | alloca(((pid ^ counter++) & 7) * 128);
|
| duke@0 |
|
| duke@0 | ThreadLocalStorage::set_thread(thread);
|
| duke@0 |
|
| duke@0 | OSThread* osthread = thread->osthread();
|
| duke@0 | Monitor* sync = osthread->startThread_lock();
|
| duke@0 |
|
| duke@0 | // non floating stack LinuxThreads needs extra check, see above
|
| duke@0 | if (!_thread_safety_check(thread)) {
|
| duke@0 | // notify parent thread
|
| duke@0 | MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
|
| duke@0 | osthread->set_state(ZOMBIE);
|
| duke@0 | sync->notify_all();
|
| duke@0 | return NULL;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // thread_id is kernel thread id (similar to Solaris LWP id)
|
| duke@0 | osthread->set_thread_id(os::Linux::gettid());
|
| duke@0 |
|
| duke@0 | if (UseNUMA) {
|
| duke@0 | int lgrp_id = os::numa_get_group_id();
|
| duke@0 | if (lgrp_id != -1) {
|
| duke@0 | thread->set_lgrp_id(lgrp_id);
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | // initialize signal mask for this thread
|
| duke@0 | os::Linux::hotspot_sigmask(thread);
|
| duke@0 |
|
| duke@0 | // initialize floating point control register
|
| duke@0 | os::Linux::init_thread_fpu_state();
|
| duke@0 |
|
| duke@0 | // handshaking with parent thread
|
| duke@0 | {
|
| duke@0 | MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
|
| duke@0 |
|
| duke@0 | // notify parent thread
|
| duke@0 | osthread->set_state(INITIALIZED);
|
| duke@0 | sync->notify_all();
|
| duke@0 |
|
| duke@0 | // wait until os::start_thread()
|
| duke@0 | while (osthread->get_state() == INITIALIZED) {
|
| duke@0 | sync->wait(Mutex::_no_safepoint_check_flag);
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // call one more level start routine
|
| duke@0 | thread->run();
|
| duke@0 |
|
| duke@0 | return 0;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
|
| duke@0 | assert(thread->osthread() == NULL, "caller responsible");
|
| duke@0 |
|
| duke@0 | // Allocate the OSThread object
|
| duke@0 | OSThread* osthread = new OSThread(NULL, NULL);
|
| duke@0 | if (osthread == NULL) {
|
| duke@0 | return false;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // set the correct thread state
|
| duke@0 | osthread->set_thread_type(thr_type);
|
| duke@0 |
|
| duke@0 | // Initial state is ALLOCATED but not INITIALIZED
|
| duke@0 | osthread->set_state(ALLOCATED);
|
| duke@0 |
|
| duke@0 | thread->set_osthread(osthread);
|
| duke@0 |
|
| duke@0 | // init thread attributes
|
| duke@0 | pthread_attr_t attr;
|
| duke@0 | pthread_attr_init(&attr);
|
| duke@0 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
| duke@0 |
|
| duke@0 | // stack size
|
| duke@0 | if (os::Linux::supports_variable_stack_size()) {
|
| duke@0 | // calculate stack size if it's not specified by caller
|
| duke@0 | if (stack_size == 0) {
|
| duke@0 | stack_size = os::Linux::default_stack_size(thr_type);
|
| duke@0 |
|
| duke@0 | switch (thr_type) {
|
| duke@0 | case os::java_thread:
|
| duke@0 | // Java threads use ThreadStackSize which default value can be changed with the flag -Xss
|
| duke@0 | if (JavaThread::stack_size_at_create() > 0) stack_size = JavaThread::stack_size_at_create();
|
| duke@0 | break;
|
| duke@0 | case os::compiler_thread:
|
| duke@0 | if (CompilerThreadStackSize > 0) {
|
| duke@0 | stack_size = (size_t)(CompilerThreadStackSize * K);
|
| duke@0 | break;
|
| duke@0 | } // else fall through:
|
| duke@0 | // use VMThreadStackSize if CompilerThreadStackSize is not defined
|
| duke@0 | case os::vm_thread:
|
| duke@0 | case os::pgc_thread:
|
| duke@0 | case os::cgc_thread:
|
| duke@0 | case os::watcher_thread:
|
| duke@0 | if (VMThreadStackSize > 0) stack_size = (size_t)(VMThreadStackSize * K);
|
| duke@0 | break;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | stack_size = MAX2(stack_size, os::Linux::min_stack_allowed);
|
| duke@0 | pthread_attr_setstacksize(&attr, stack_size);
|
| duke@0 | } else {
|
| duke@0 | // let pthread_create() pick the default value.
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // glibc guard page
|
| duke@0 | pthread_attr_setguardsize(&attr, os::Linux::default_guard_size(thr_type));
|
| duke@0 |
|
| duke@0 | ThreadState state;
|
| duke@0 |
|
| duke@0 | {
|
| duke@0 | // Serialize thread creation if we are running with fixed stack LinuxThreads
|
| duke@0 | bool lock = os::Linux::is_LinuxThreads() && !os::Linux::is_floating_stack();
|
| duke@0 | if (lock) {
|
| duke@0 | os::Linux::createThread_lock()->lock_without_safepoint_check();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | pthread_t tid;
|
| duke@0 | int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);
|
| duke@0 |
|
| duke@0 | pthread_attr_destroy(&attr);
|
| duke@0 |
|
| duke@0 | if (ret != 0) {
|
| duke@0 | if (PrintMiscellaneous && (Verbose || WizardMode)) {
|
| duke@0 | perror("pthread_create()");
|
| duke@0 | }
|
| duke@0 | // Need to clean up stuff we've allocated so far
|
| duke@0 | thread->set_osthread(NULL);
|
| duke@0 | delete osthread;
|
| duke@0 | if (lock) os::Linux::createThread_lock()->unlock();
|
| duke@0 | return false;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Store pthread info into the OSThread
|
| duke@0 | osthread->set_pthread_id(tid);
|
| duke@0 |
|
| duke@0 | // Wait until child thread is either initialized or aborted
|
| duke@0 | {
|
| duke@0 | Monitor* sync_with_child = osthread->startThread_lock();
|
| duke@0 | MutexLockerEx ml(sync_with_child, Mutex::_no_safepoint_check_flag);
|
| duke@0 | while ((state = osthread->get_state()) == ALLOCATED) {
|
| duke@0 | sync_with_child->wait(Mutex::_no_safepoint_check_flag);
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | if (lock) {
|
| duke@0 | os::Linux::createThread_lock()->unlock();
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Aborted due to thread limit being reached
|
| duke@0 | if (state == ZOMBIE) {
|
| duke@0 | thread->set_osthread(NULL);
|
| duke@0 | delete osthread;
|
| duke@0 | return false;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // The thread is returned suspended (in state INITIALIZED),
|
| duke@0 | // and is started higher up in the call chain
|
| duke@0 | assert(state == INITIALIZED, "race condition");
|
| duke@0 | return true;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | /////////////////////////////////////////////////////////////////////////////
|
| duke@0 | // attach existing thread
|
| duke@0 |
|
| duke@0 | // bootstrap the main thread
|
| duke@0 | bool os::create_main_thread(JavaThread* thread) {
|
| duke@0 | assert(os::Linux::_main_thread == pthread_self(), "should be called inside main thread");
|
| duke@0 | return create_attached_thread(thread);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | bool os::create_attached_thread(JavaThread* thread) {
|
| duke@0 | #ifdef ASSERT
|
| duke@0 | thread->verify_not_published();
|
| duke@0 | #endif
|
| duke@0 |
|
| duke@0 | // Allocate the OSThread object
|
| duke@0 | OSThread* osthread = new OSThread(NULL, NULL);
|
| duke@0 |
|
| duke@0 | if (osthread == NULL) {
|
| duke@0 | return false;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Store pthread info into the OSThread
|
| duke@0 | osthread->set_thread_id(os::Linux::gettid());
|
| duke@0 | osthread->set_pthread_id(::pthread_self());
|
| duke@0 |
|
| duke@0 | // initialize floating point control register
|
| duke@0 | os::Linux::init_thread_fpu_state();
|
| duke@0 |
|
| duke@0 | // Initial thread state is RUNNABLE
|
| duke@0 | osthread->set_state(RUNNABLE);
|
| duke@0 |
|
| duke@0 | thread->set_osthread(osthread);
|
| duke@0 |
|
| duke@0 | if (UseNUMA) {
|
| duke@0 | int lgrp_id = os::numa_get_group_id();
|
| duke@0 | if (lgrp_id != -1) {
|
| duke@0 | thread->set_lgrp_id(lgrp_id);
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | if (os::Linux::is_initial_thread()) {
|
| duke@0 | // If current thread is initial thread, its stack is mapped on demand,
|
| duke@0 | // see notes about MAP_GROWSDOWN. Here we try to force kernel to map
|
| duke@0 | // the entire stack region to avoid SEGV in stack banging.
|
| duke@0 | // It is also useful to get around the heap-stack-gap problem on SuSE
|
| duke@0 | // kernel (see 4821821 for details). We first expand stack to the top
|
| duke@0 | // of yellow zone, then enable stack yellow zone (order is significant,
|
| duke@0 | // enabling yellow zone first will crash JVM on SuSE Linux), so there
|
| duke@0 | // is no gap between the last two virtual memory regions.
|
| duke@0 |
|
| duke@0 | JavaThread *jt = (JavaThread *)thread;
|
| duke@0 | address addr = jt->stack_yellow_zone_base();
|
| duke@0 | assert(addr != NULL, "initialization problem?");
|
| duke@0 | assert(jt->stack_available(addr) > 0, "stack guard should not be enabled");
|
| duke@0 |
|
| duke@0 | osthread->set_expanding_stack();
|
| duke@0 | os::Linux::manually_expand_stack(jt, addr);
|
| duke@0 | osthread->clear_expanding_stack();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // initialize signal mask for this thread
|
| duke@0 | // and save the caller's signal mask
|
| duke@0 | os::Linux::hotspot_sigmask(thread);
|
| duke@0 |
|
| duke@0 | return true;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | void os::pd_start_thread(Thread* thread) {
|
| duke@0 | OSThread * osthread = thread->osthread();
|
| duke@0 | assert(osthread->get_state() != INITIALIZED, "just checking");
|
| duke@0 | Monitor* sync_with_child = osthread->startThread_lock();
|
| duke@0 | MutexLockerEx ml(sync_with_child, Mutex::_no_safepoint_check_flag);
|
| duke@0 | sync_with_child->notify();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Free Linux resources related to the OSThread
|
| duke@0 | void os::free_thread(OSThread* osthread) {
|
| duke@0 | assert(osthread != NULL, "osthread not set");
|
| duke@0 |
|
| duke@0 | if (Thread::current()->osthread() == osthread) {
|
| duke@0 | // Restore caller's signal mask
|
| duke@0 | sigset_t sigmask = osthread->caller_sigmask();
|
| duke@0 | pthread_sigmask(SIG_SETMASK, &sigmask, NULL);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | delete osthread;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | //////////////////////////////////////////////////////////////////////////////
|
| duke@0 | // thread local storage
|
| duke@0 |
|
| duke@0 | int os::allocate_thread_local_storage() {
|
| duke@0 | pthread_key_t key;
|
| duke@0 | int rslt = pthread_key_create(&key, NULL);
|
| duke@0 | assert(rslt == 0, "cannot allocate thread local storage");
|
| duke@0 | return (int)key;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Note: This is currently not used by VM, as we don't destroy TLS key
|
| duke@0 | // on VM exit.
|
| duke@0 | void os::free_thread_local_storage(int index) {
|
| duke@0 | int rslt = pthread_key_delete((pthread_key_t)index);
|
| duke@0 | assert(rslt == 0, "invalid index");
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | void os::thread_local_storage_at_put(int index, void* value) {
|
| duke@0 | int rslt = pthread_setspecific((pthread_key_t)index, value);
|
| duke@0 | assert(rslt == 0, "pthread_setspecific failed");
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | extern "C" Thread* get_thread() {
|
| duke@0 | return ThreadLocalStorage::thread();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | //////////////////////////////////////////////////////////////////////////////
|
| duke@0 | // initial thread
|
| duke@0 |
|
| duke@0 | // Check if current thread is the initial thread, similar to Solaris thr_main.
|
| duke@0 | bool os::Linux::is_initial_thread(void) {
|
| duke@0 | char dummy;
|
| duke@0 | // If called before init complete, thread stack bottom will be null.
|
| duke@0 | // Can be called if fatal error occurs before initialization.
|
| duke@0 | if (initial_thread_stack_bottom() == NULL) return false;
|
| duke@0 | assert(initial_thread_stack_bottom() != NULL &&
|
| duke@0 | initial_thread_stack_size() != 0,
|
| duke@0 | "os::init did not locate initial thread's stack region");
|
| duke@0 | if ((address)&dummy >= initial_thread_stack_bottom() &&
|
| duke@0 | (address)&dummy < initial_thread_stack_bottom() + initial_thread_stack_size())
|
| duke@0 | return true;
|
| duke@0 | else return false;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Find the virtual memory area that contains addr
|
| duke@0 | static bool find_vma(address addr, address* vma_low, address* vma_high) {
|
| duke@0 | FILE *fp = fopen("/proc/self/maps", "r");
|
| duke@0 | if (fp) {
|
| duke@0 | address low, high;
|
| duke@0 | while (!feof(fp)) {
|
| duke@0 | if (fscanf(fp, "%p-%p", &low, &high) == 2) {
|
| duke@0 | if (low <= addr && addr < high) {
|
| duke@0 | if (vma_low) *vma_low = low;
|
| duke@0 | if (vma_high) *vma_high = high;
|
| duke@0 | fclose (fp);
|
| duke@0 | return true;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | for (;;) {
|
| duke@0 | int ch = fgetc(fp);
|
| duke@0 | if (ch == EOF || ch == (int)'\n') break;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | fclose(fp);
|
| duke@0 | }
|
| duke@0 | return false;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Locate initial thread stack. This special handling of initial thread stack
|
| duke@0 | // is needed because pthread_getattr_np() on most (all?) Linux distros returns
|
| duke@0 | // bogus value for initial thread.
|
| duke@0 | void os::Linux::capture_initial_stack(size_t max_size) {
|
| duke@0 | // stack size is the easy part, get it from RLIMIT_STACK
|
| duke@0 | size_t stack_size;
|
| duke@0 | struct rlimit rlim;
|
| duke@0 | getrlimit(RLIMIT_STACK, &rlim);
|
| duke@0 | stack_size = rlim.rlim_cur;
|
| duke@0 |
|
| duke@0 | // 6308388: a bug in ld.so will relocate its own .data section to the
|
| duke@0 | // lower end of primordial stack; reduce ulimit -s value a little bit
|
| duke@0 | // so we won't install guard page on ld.so's data section.
|
| duke@0 | stack_size -= 2 * page_size();
|
| duke@0 |
|
| duke@0 | // 4441425: avoid crash with "unlimited" stack size on SuSE 7.1 or Redhat
|
| duke@0 | // 7.1, in both cases we will get 2G in return value.
|
| duke@0 | // 4466587: glibc 2.2.x compiled w/o "--enable-kernel=2.4.0" (RH 7.0,
|
| duke@0 | // SuSE 7.2, Debian) can not handle alternate signal stack correctly
|
| duke@0 | // for initial thread if its stack size exceeds 6M. Cap it at 2M,
|
| duke@0 | // in case other parts in glibc still assumes 2M max stack size.
|
| duke@0 | // FIXME: alt signal stack is gone, maybe we can relax this constraint?
|
| duke@0 | #ifndef IA64
|
| duke@0 | if (stack_size > 2 * K * K) stack_size = 2 * K * K;
|
| duke@0 | #else
|
| duke@0 | // Problem still exists RH7.2 (IA64 anyway) but 2MB is a little small
|
| duke@0 | if (stack_size > 4 * K * K) stack_size = 4 * K * K;
|
| duke@0 | #endif
|
| duke@0 |
|
| duke@0 | // Try to figure out where the stack base (top) is. This is harder.
|
| duke@0 | //
|
| duke@0 | // When an application is started, glibc saves the initial stack pointer in
|
| duke@0 | // a global variable "__libc_stack_end", which is then used by system
|
| duke@0 | // libraries. __libc_stack_end should be pretty close to stack top. The
|
| duke@0 | // variable is available since the very early days. However, because it is
|
| duke@0 | // a private interface, it could disappear in the future.
|
| duke@0 | //
|
| duke@0 | // Linux kernel saves start_stack information in /proc/<pid>/stat. Similar
|
| duke@0 | // to __libc_stack_end, it is very close to stack top, but isn't the real
|
| duke@0 | // stack top. Note that /proc may not exist if VM is running as a chroot
|
| duke@0 | // program, so reading /proc/<pid>/stat could fail. Also the contents of
|
| duke@0 | // /proc/<pid>/stat could change in the future (though unlikely).
|
| duke@0 | //
|
| duke@0 | // We try __libc_stack_end first. If that doesn't work, look for
|
| duke@0 | // /proc/<pid>/stat. If neither of them works, we use current stack pointer
|
| duke@0 | // as a hint, which should work well in most cases.
|
| duke@0 |
|
| duke@0 | uintptr_t stack_start;
|
| duke@0 |
|
| duke@0 | // try __libc_stack_end first
|
| duke@0 | uintptr_t *p = (uintptr_t *)dlsym(RTLD_DEFAULT, "__libc_stack_end");
|
| duke@0 | if (p && *p) {
|
| duke@0 | stack_start = *p;
|
| duke@0 | } else {
|
| duke@0 | // see if we can get the start_stack field from /proc/self/stat
|
| duke@0 | FILE *fp;
|
| duke@0 | int pid;
|
| duke@0 | char state;
|
| duke@0 | int ppid;
|
| duke@0 | int pgrp;
|
| duke@0 | int session;
|
| duke@0 | int nr;
|
| duke@0 | int tpgrp;
|
| duke@0 | unsigned long flags;
|
| duke@0 | unsigned long minflt;
|
| duke@0 | unsigned long cminflt;
|
| duke@0 | unsigned long majflt;
|
| duke@0 | unsigned long cmajflt;
|
| duke@0 | unsigned long utime;
|
| duke@0 | unsigned long stime;
|
| duke@0 | long cutime;
|
| duke@0 | long cstime;
|
| duke@0 | long prio;
|
| duke@0 | long nice;
|
| duke@0 | long junk;
|
| duke@0 | long it_real;
|
| duke@0 | uintptr_t start;
|
| duke@0 | uintptr_t vsize;
|
| bobv@1892 | intptr_t rss;
|
| bobv@1892 | uintptr_t rsslim;
|
| duke@0 | uintptr_t scodes;
|
| duke@0 | uintptr_t ecode;
|
| duke@0 | int i;
|
| duke@0 |
|
| duke@0 | // Figure what the primordial thread stack base is. Code is inspired
|
| duke@0 | // by email from Hans Boehm. /proc/self/stat begins with current pid,
|
| duke@0 | // followed by command name surrounded by parentheses, state, etc.
|
| duke@0 | char stat[2048];
|
| duke@0 | int statlen;
|
| duke@0 |
|
| duke@0 | fp = fopen("/proc/self/stat", "r");
|
| duke@0 | if (fp) {
|
| duke@0 | statlen = fread(stat, 1, 2047, fp);
|
| duke@0 | stat[statlen] = '\0';
|
| duke@0 | fclose(fp);
|
| duke@0 |
|
| duke@0 | // Skip pid and the command string. Note that we could be dealing with
|
| duke@0 | // weird command names, e.g. user could decide to rename java launcher
|
| duke@0 | // to "java 1.4.2 :)", then the stat file would look like
|
| duke@0 | // 1234 (java 1.4.2 :)) R ... ...
|
| duke@0 | // We don't really need to know the command string, just find the last
|
| duke@0 | // occurrence of ")" and then start parsing from there. See bug 4726580.
|
| duke@0 | char * s = strrchr(stat, ')');
|
| duke@0 |
|
| duke@0 | i = 0;
|
| duke@0 | if (s) {
|
| duke@0 | // Skip blank chars
|
| duke@0 | do s++; while (isspace(*s));
|
| duke@0 |
|
| bobv@1892 | #define _UFM UINTX_FORMAT
|
| bobv@1892 | #define _DFM INTX_FORMAT
|
| bobv@1892 |
|
| bobv@1892 | /* 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 */
|
| bobv@1892 | /* 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 */
|
| bobv@1892 | i = sscanf(s, "%c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld " _UFM _UFM _DFM _UFM _UFM _UFM _UFM,
|
| duke@0 | &state, /* 3 %c */
|
| duke@0 | &ppid, /* 4 %d */
|
| duke@0 | &pgrp, /* 5 %d */
|
| duke@0 | &session, /* 6 %d */
|
| duke@0 | &nr, /* 7 %d */
|
| duke@0 | &tpgrp, /* 8 %d */
|
| duke@0 | &flags, /* 9 %lu */
|
| duke@0 | &minflt, /* 10 %lu */
|
| duke@0 | &cminflt, /* 11 %lu */
|
| duke@0 | &majflt, /* 12 %lu */
|
| duke@0 | &cmajflt, /* 13 %lu */
|
| duke@0 | &utime, /* 14 %lu */
|
| duke@0 | &stime, /* 15 %lu */
|
| duke@0 | &cutime, /* 16 %ld */
|
| duke@0 | &cstime, /* 17 %ld */
|
| duke@0 | &prio, /* 18 %ld */
|
| duke@0 | &nice, /* 19 %ld */
|
| duke@0 | &junk, /* 20 %ld */
|
| duke@0 | &it_real, /* 21 %ld */
|
| bobv@1892 | &start, /* 22 UINTX_FORMAT */
|
| bobv@1892 | &vsize, /* 23 UINTX_FORMAT */
|
| bobv@1892 | &rss, /* 24 INTX_FORMAT */
|
| bobv@1892 | &rsslim, /* 25 UINTX_FORMAT */
|
| bobv@1892 | &scodes, /* 26 UINTX_FORMAT */
|
| bobv@1892 | &ecode, /* 27 UINTX_FORMAT */
|
| bobv@1892 | &stack_start); /* 28 UINTX_FORMAT */
|
| duke@0 | }
|
| bobv@1892 |
|
| bobv@1892 | #undef _UFM
|
| bobv@1892 | #undef _DFM
|
| duke@0 |
|
| duke@0 | if (i != 28 - 2) {
|
| duke@0 | assert(false, "Bad conversion from /proc/self/stat");
|
| duke@0 | // product mode - assume we are the initial thread, good luck in the
|
| duke@0 | // embedded case.
|
| duke@0 | warning("Can't detect initial thread stack location - bad conversion");
|
| duke@0 | stack_start = (uintptr_t) &rlim;
|
| duke@0 | }
|
| duke@0 | } else {
|
| duke@0 | // For some reason we can't open /proc/self/stat (for example, running on
|
| duke@0 | // FreeBSD with a Linux emulator, or inside chroot), this should work for
|
| duke@0 | // most cases, so don't abort:
|
| duke@0 | warning("Can't detect initial thread stack location - no /proc/self/stat");
|
| duke@0 | stack_start = (uintptr_t) &rlim;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Now we have a pointer (stack_start) very close to the stack top, the
|
| duke@0 | // next thing to do is to figure out the exact location of stack top. We
|
| duke@0 | // can find out the virtual memory area that contains stack_start by
|
| duke@0 | // reading /proc/self/maps, it should be the last vma in /proc/self/maps,
|
| duke@0 | // and its upper limit is the real stack top. (again, this would fail if
|
| duke@0 | // running inside chroot, because /proc may not exist.)
|
| duke@0 |
|
| duke@0 | uintptr_t stack_top;
|
| duke@0 | address low, high;
|
| duke@0 | if (find_vma((address)stack_start, &low, &high)) {
|
| duke@0 | // success, "high" is the true stack top. (ignore "low", because initial
|
| duke@0 | // thread stack grows on demand, its real bottom is high - RLIMIT_STACK.)
|
| duke@0 | stack_top = (uintptr_t)high;
|
| duke@0 | } else {
|
| duke@0 | // failed, likely because /proc/self/maps does not exist
|
| duke@0 | warning("Can't detect initial thread stack location - find_vma failed");
|
| duke@0 | // best effort: stack_start is normally within a few pages below the real
|
| duke@0 | // stack top, use it as stack top, and reduce stack size so we won't put
|
| duke@0 | // guard page outside stack.
|
| duke@0 | stack_top = stack_start;
|
| duke@0 | stack_size -= 16 * page_size();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // stack_top could be partially down the page so align it
|
| duke@0 | stack_top = align_size_up(stack_top, page_size());
|
| duke@0 |
|
| duke@0 | if (max_size && stack_size > max_size) {
|
| duke@0 | _initial_thread_stack_size = max_size;
|
| duke@0 | } else {
|
| duke@0 | _initial_thread_stack_size = stack_size;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | _initial_thread_stack_size = align_size_down(_initial_thread_stack_size, page_size());
|
| duke@0 | _initial_thread_stack_bottom = (address)stack_top - _initial_thread_stack_size;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | ////////////////////////////////////////////////////////////////////////////////
|
| duke@0 | // time support
|
| duke@0 |
|
| duke@0 | // Time since start-up in seconds to a fine granularity.
|
| duke@0 | // Used by VMSelfDestructTimer and the MemProfiler.
|
| duke@0 | double os::elapsedTime() {
|
| duke@0 |
|
| duke@0 | return (double)(os::elapsed_counter()) * 0.000001;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | jlong os::elapsed_counter() {
|
| duke@0 | timeval time;
|
| duke@0 | int status = gettimeofday(&time, NULL);
|
| duke@0 | return jlong(time.tv_sec) * 1000 * 1000 + jlong(time.tv_usec) - initial_time_count;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | jlong os::elapsed_frequency() {
|
| duke@0 | return (1000 * 1000);
|
| ysr@397 | }
|
| ysr@397 |
|
| ysr@397 | // For now, we say that linux does not support vtime. I have no idea
|
| ysr@397 | // whether it can actually be made to (DLD, 9/13/05).
|
| ysr@397 |
|
| ysr@397 | bool os::supports_vtime() { return false; }
|
| ysr@397 | bool os::enable_vtime() { return false; }
|
| ysr@397 | bool os::vtime_enabled() { return false; }
|
| ysr@397 | double os::elapsedVTime() {
|
| ysr@397 | // better than nothing, but not much
|
| ysr@397 | return elapsedTime();
|
| duke@0 | }
|
| duke@0 |
|
| sbohne@119 | jlong os::javaTimeMillis() {
|
| duke@0 | timeval time;
|
| duke@0 | int status = gettimeofday(&time, NULL);
|
| duke@0 | assert(status != -1, "linux error");
|
| duke@0 | return jlong(time.tv_sec) * 1000 + jlong(time.tv_usec / 1000);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | #ifndef CLOCK_MONOTONIC
|
| duke@0 | #define CLOCK_MONOTONIC (1)
|
| duke@0 | #endif
|
| duke@0 |
|
| duke@0 | void os::Linux::clock_init() {
|
| duke@0 | // we do dlopen's in this particular order due to bug in linux
|
| duke@0 | // dynamical loader (see 6348968) leading to crash on exit
|
| duke@0 | void* handle = dlopen("librt.so.1", RTLD_LAZY);
|
| duke@0 | if (handle == NULL) {
|
| duke@0 | handle = dlopen("librt.so", RTLD_LAZY);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | if (handle) {
|
| duke@0 | int (*clock_getres_func)(clockid_t, struct timespec*) =
|
| duke@0 | (int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_getres");
|
| duke@0 | int (*clock_gettime_func)(clockid_t, struct timespec*) =
|
| duke@0 | (int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_gettime");
|
| duke@0 | if (clock_getres_func && clock_gettime_func) {
|
| duke@0 | // See if monotonic clock is supported by the kernel. Note that some
|
| duke@0 | // early implementations simply return kernel jiffies (updated every
|
| duke@0 | // 1/100 or 1/1000 second). It would be bad to use such a low res clock
|
| duke@0 | // for nano time (though the monotonic property is still nice to have).
|
| duke@0 | // It's fixed in newer kernels, however clock_getres() still returns
|
| duke@0 | // 1/HZ. We check if clock_getres() works, but will ignore its reported
|
| duke@0 | // resolution for now. Hopefully as people move to new kernels, this
|
| duke@0 | // won't be a problem.
|
| duke@0 | struct timespec res;
|
| duke@0 | struct timespec tp;
|
| duke@0 | if (clock_getres_func (CLOCK_MONOTONIC, &res) == 0 &&
|
| duke@0 | clock_gettime_func(CLOCK_MONOTONIC, &tp) == 0) {
|
| duke@0 | // yes, monotonic clock is supported
|
| duke@0 | _clock_gettime = clock_gettime_func;
|
| duke@0 | } else {
|
| duke@0 | // close librt if there is no monotonic clock
|
| duke@0 | dlclose(handle);
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | #ifndef SYS_clock_getres
|
| duke@0 |
|
| duke@0 | #if defined(IA32) || defined(AMD64)
|
| duke@0 | #define SYS_clock_getres IA32_ONLY(266) AMD64_ONLY(229)
|
| bobv@1892 | #define sys_clock_getres(x,y) ::syscall(SYS_clock_getres, x, y)
|
| duke@0 | #else
|
| bobv@1892 | #warning "SYS_clock_getres not defined for this platform, disabling fast_thread_cpu_time"
|
| bobv@1892 | #define sys_clock_getres(x,y) -1
|
| duke@0 | #endif
|
| duke@0 |
|
| bobv@1892 | #else
|
| bobv@1892 | #define sys_clock_getres(x,y) ::syscall(SYS_clock_getres, x, y)
|
| duke@0 | #endif
|
| duke@0 |
|
| duke@0 | void os::Linux::fast_thread_clock_init() {
|
| duke@0 | if (!UseLinuxPosixThreadCPUClocks) {
|
| duke@0 | return;
|
| duke@0 | }
|
| duke@0 | clockid_t clockid;
|
| duke@0 | struct timespec tp;
|
| duke@0 | int (*pthread_getcpuclockid_func)(pthread_t, clockid_t *) =
|
| duke@0 | (int(*)(pthread_t, clockid_t *)) dlsym(RTLD_DEFAULT, "pthread_getcpuclockid");
|
| duke@0 |
|
| duke@0 | // Switch to using fast clocks for thread cpu time if
|
| duke@0 | // the sys_clock_getres() returns 0 error code.
|
| duke@0 | // Note, that some kernels may support the current thread
|
| duke@0 | // clock (CLOCK_THREAD_CPUTIME_ID) but not the clocks
|
| duke@0 | // returned by the pthread_getcpuclockid().
|
| duke@0 | // If the fast Posix clocks are supported then the sys_clock_getres()
|
| duke@0 | // must return at least tp.tv_sec == 0 which means a resolution
|
| duke@0 | // better than 1 sec. This is extra check for reliability.
|
| duke@0 |
|
| duke@0 | if(pthread_getcpuclockid_func &&
|
| duke@0 | pthread_getcpuclockid_func(_main_thread, &clockid) == 0 &&
|
| duke@0 | sys_clock_getres(clockid, &tp) == 0 && tp.tv_sec == 0) {
|
| duke@0 |
|
| duke@0 | _supports_fast_thread_cpu_time = true;
|
| duke@0 | _pthread_getcpuclockid = pthread_getcpuclockid_func;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | jlong os::javaTimeNanos() {
|
| duke@0 | if (Linux::supports_monotonic_clock()) {
|
| duke@0 | struct timespec tp;
|
| duke@0 | int status = Linux::clock_gettime(CLOCK_MONOTONIC, &tp);
|
| duke@0 | assert(status == 0, "gettime error");
|
| duke@0 | jlong result = jlong(tp.tv_sec) * (1000 * 1000 * 1000) + jlong(tp.tv_nsec);
|
| duke@0 | return result;
|
| duke@0 | } else {
|
| duke@0 | timeval time;
|
| duke@0 | int status = gettimeofday(&time, NULL);
|
| duke@0 | assert(status != -1, "linux error");
|
| duke@0 | jlong usecs = jlong(time.tv_sec) * (1000 * 1000) + jlong(time.tv_usec);
|
| duke@0 | return 1000 * usecs;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) {
|
| duke@0 | if (Linux::supports_monotonic_clock()) {
|
| duke@0 | info_ptr->max_value = ALL_64_BITS;
|
| duke@0 |
|
| duke@0 | // CLOCK_MONOTONIC - amount of time since some arbitrary point in the past
|
| duke@0 | info_ptr->may_skip_backward = false; // not subject to resetting or drifting
|
| duke@0 | info_ptr->may_skip_forward = false; // not subject to resetting or drifting
|
| duke@0 | } else {
|
| duke@0 | // gettimeofday - based on time in seconds since the Epoch thus does not wrap
|
| duke@0 | info_ptr->max_value = ALL_64_BITS;
|
| duke@0 |
|
| duke@0 | // gettimeofday is a real time clock so it skips
|
| duke@0 | info_ptr->may_skip_backward = true;
|
| duke@0 | info_ptr->may_skip_forward = true;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | info_ptr->kind = JVMTI_TIMER_ELAPSED; // elapsed not CPU time
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Return the real, user, and system times in seconds from an
|
| duke@0 | // arbitrary fixed point in the past.
|
| duke@0 | bool os::getTimesSecs(double* process_real_time,
|
| duke@0 | double* process_user_time,
|
| duke@0 | double* process_system_time) {
|
| duke@0 | struct tms ticks;
|
| duke@0 | clock_t real_ticks = times(&ticks);
|
| duke@0 |
|
| duke@0 | if (real_ticks == (clock_t) (-1)) {
|
| duke@0 | return false;
|
| duke@0 | } else {
|
| duke@0 | double ticks_per_second = (double) clock_tics_per_sec;
|
| duke@0 | *process_user_time = ((double) ticks.tms_utime) / ticks_per_second;
|
| duke@0 | *process_system_time = ((double) ticks.tms_stime) / ticks_per_second;
|
| duke@0 | *process_real_time = ((double) real_ticks) / ticks_per_second;
|
| duke@0 |
|
| duke@0 | return true;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 |
|
| duke@0 | char * os::local_time_string(char *buf, size_t buflen) {
|
| duke@0 | struct tm t;
|
| duke@0 | time_t long_time;
|
| duke@0 | time(&long_time);
|
| duke@0 | localtime_r(&long_time, &t);
|
| duke@0 | jio_snprintf(buf, buflen, "%d-%02d-%02d %02d:%02d:%02d",
|
| duke@0 | t.tm_year + 1900, t.tm_mon + 1, t.tm_mday,
|
| duke@0 | t.tm_hour, t.tm_min, t.tm_sec);
|
| duke@0 | return buf;
|
| ysr@678 | }
|
| ysr@678 |
|
| ysr@678 | struct tm* os::localtime_pd(const time_t* clock, struct tm* res) {
|
| ysr@678 | return localtime_r(clock, res);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | ////////////////////////////////////////////////////////////////////////////////
|
| duke@0 | // runtime exit support
|
| duke@0 |
|
| duke@0 | // Note: os::shutdown() might be called very early during initialization, or
|
| duke@0 | // called from signal handler. Before adding something to os::shutdown(), make
|
| duke@0 | // sure it is async-safe and can handle partially initialized VM.
|
| duke@0 | void os::shutdown() {
|
| duke@0 |
|
| duke@0 | // allow PerfMemory to attempt cleanup of any persistent resources
|
| duke@0 | perfMemory_exit();
|
| duke@0 |
|
| duke@0 | // needs to remove object in file system
|
| duke@0 | AttachListener::abort();
|
| duke@0 |
|
| duke@0 | // flush buffered output, finish log files
|
| duke@0 | ostream_abort();
|
| duke@0 |
|
| duke@0 | // Check for abort hook
|
| duke@0 | abort_hook_t abort_hook = Arguments::abort_hook();
|
| duke@0 | if (abort_hook != NULL) {
|
| duke@0 | abort_hook();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Note: os::abort() might be called very early during initialization, or
|
| duke@0 | // called from signal handler. Before adding something to os::abort(), make
|
| duke@0 | // sure it is async-safe and can handle partially initialized VM.
|
| duke@0 | void os::abort(bool dump_core) {
|
| duke@0 | os::shutdown();
|
| duke@0 | if (dump_core) {
|
| duke@0 | #ifndef PRODUCT
|
| duke@0 | fdStream out(defaultStream::output_fd());
|
| duke@0 | out.print_raw("Current thread is ");
|
| duke@0 | char buf[16];
|
| duke@0 | jio_snprintf(buf, sizeof(buf), UINTX_FORMAT, os::current_thread_id());
|
| duke@0 | out.print_raw_cr(buf);
|
| duke@0 | out.print_raw_cr("Dumping core ...");
|
| duke@0 | #endif
|
| duke@0 | ::abort(); // dump core
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | ::exit(1);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Die immediately, no exit hook, no abort hook, no cleanup.
|
| duke@0 | void os::die() {
|
| duke@0 | // _exit() on LinuxThreads only kills current thread
|
| duke@0 | ::abort();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // unused on linux for now.
|
| duke@0 | void os::set_error_file(const char *logfile) {}
|
| duke@0 |
|
| duke@0 | intx os::current_thread_id() { return (intx)pthread_self(); }
|
| duke@0 | int os::current_process_id() {
|
| duke@0 |
|
| duke@0 | // Under the old linux thread library, linux gives each thread
|
| duke@0 | // its own process id. Because of this each thread will return
|
| duke@0 | // a different pid if this method were to return the result
|
| duke@0 | // of getpid(2). Linux provides no api that returns the pid
|
| duke@0 | // of the launcher thread for the vm. This implementation
|
| duke@0 | // returns a unique pid, the pid of the launcher thread
|
| duke@0 | // that starts the vm 'process'.
|
| duke@0 |
|
| duke@0 | // Under the NPTL, getpid() returns the same pid as the
|
| duke@0 | // launcher thread rather than a unique pid per thread.
|
| duke@0 | // Use gettid() if you want the old pre NPTL behaviour.
|
| duke@0 |
|
| duke@0 | // if you are looking for the result of a call to getpid() that
|
| duke@0 | // returns a unique pid for the calling thread, then look at the
|
| duke@0 | // OSThread::thread_id() method in osThread_linux.hpp file
|
| duke@0 |
|
| duke@0 | return (int)(_initial_pid ? _initial_pid : getpid());
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // DLL functions
|
| duke@0 |
|
| duke@0 | const char* os::dll_file_extension() { return ".so"; }
|
| duke@0 |
|
| coleenp@1999 | // This must be hard coded because it's the system's temporary
|
| coleenp@1999 | // directory not the java application's temp directory, ala java.io.tmpdir.
|
| coleenp@1999 | const char* os::get_temp_directory() { return "/tmp"; }
|
| duke@0 |
|
| phh@819 | static bool file_exists(const char* filename) {
|
| phh@819 | struct stat statbuf;
|
| phh@819 | if (filename == NULL || strlen(filename) == 0) {
|
| phh@819 | return false;
|
| phh@819 | }
|
| phh@819 | return os::stat(filename, &statbuf) == 0;
|
| phh@819 | }
|
| phh@819 |
|
| phh@819 | void os::dll_build_name(char* buffer, size_t buflen,
|
| phh@819 | const char* pname, const char* fname) {
|
| phh@819 | // Copied from libhpi
|
| kamg@299 | const size_t pnamelen = pname ? strlen(pname) : 0;
|
| kamg@299 |
|
| phh@819 | // Quietly truncate on buffer overflow. Should be an error.
|
| kamg@299 | if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
|
| phh@592 | *buffer = '\0';
|
| phh@592 | return;
|
| kamg@299 | }
|
| kamg@299 |
|
| kamg@299 | if (pnamelen == 0) {
|
| phh@819 | snprintf(buffer, buflen, "lib%s.so", fname);
|
| phh@819 | } else if (strchr(pname, *os::path_separator()) != NULL) {
|
| phh@819 | int n;
|
| phh@819 | char** pelements = split_path(pname, &n);
|
| phh@819 | for (int i = 0 ; i < n ; i++) {
|
| phh@819 | // Really shouldn't be NULL, but check can't hurt
|
| phh@819 | if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
|
| phh@819 | continue; // skip the empty path values
|
| phh@819 | }
|
| phh@819 | snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname);
|
| phh@819 | if (file_exists(buffer)) {
|
| phh@819 | break;
|
| phh@819 | }
|
| phh@819 | }
|
| phh@819 | // release the storage
|
| phh@819 | for (int i = 0 ; i < n ; i++) {
|
| phh@819 | if (pelements[i] != NULL) {
|
| phh@819 | FREE_C_HEAP_ARRAY(char, pelements[i]);
|
| phh@819 | }
|
| phh@819 | }
|
| phh@819 | if (pelements != NULL) {
|
| phh@819 | FREE_C_HEAP_ARRAY(char*, pelements);
|
| phh@819 | }
|
| kamg@299 | } else {
|
| phh@819 | snprintf(buffer, buflen, "%s/lib%s.so", pname, fname);
|
| kamg@299 | }
|
| kamg@299 | }
|
| kamg@299 |
|
| duke@0 | const char* os::get_current_directory(char *buf, int buflen) {
|
| duke@0 | return getcwd(buf, buflen);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // check if addr is inside libjvm[_g].so
|
| duke@0 | bool os::address_is_in_vm(address addr) {
|
| duke@0 | static address libjvm_base_addr;
|
| duke@0 | Dl_info dlinfo;
|
| duke@0 |
|
| duke@0 | if (libjvm_base_addr == NULL) {
|
| duke@0 | dladdr(CAST_FROM_FN_PTR(void *, os::address_is_in_vm), &dlinfo);
|
| duke@0 | libjvm_base_addr = (address)dlinfo.dli_fbase;
|
| duke@0 | assert(libjvm_base_addr !=NULL, "Cannot obtain base address for libjvm");
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | if (dladdr((void *)addr, &dlinfo)) {
|
| duke@0 | if (libjvm_base_addr == (address)dlinfo.dli_fbase) return true;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | return false;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | bool os::dll_address_to_function_name(address addr, char *buf,
|
| duke@0 | int buflen, int *offset) {
|
| duke@0 | Dl_info dlinfo;
|
| duke@0 |
|
| duke@0 | if (dladdr((void*)addr, &dlinfo) && dlinfo.dli_sname != NULL) {
|
| duke@0 | if (buf) jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname);
|
| duke@0 | if (offset) *offset = addr - (address)dlinfo.dli_saddr;
|
| duke@0 | return true;
|
| duke@0 | } else {
|
| duke@0 | if (buf) buf[0] = '\0';
|
| duke@0 | if (offset) *offset = -1;
|
| duke@0 | return false;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | struct _address_to_library_name {
|
| duke@0 | address addr; // input : memory address
|
| duke@0 | size_t buflen; // size of fname
|
| duke@0 | char* fname; // output: library name
|
| duke@0 | address base; // library base addr
|
| duke@0 | };
|
| duke@0 |
|
| duke@0 | static int address_to_library_name_callback(struct dl_phdr_info *info,
|
| duke@0 | size_t size, void *data) {
|
| duke@0 | int i;
|
| duke@0 | bool found = false;
|
| duke@0 | address libbase = NULL;
|
| duke@0 | struct _address_to_library_name * d = (struct _address_to_library_name *)data;
|
| duke@0 |
|
| duke@0 | // iterate through all loadable segments
|
| duke@0 | for (i = 0; i < info->dlpi_phnum; i++) {
|
| duke@0 | address segbase = (address)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
|
| duke@0 | if (info->dlpi_phdr[i].p_type == PT_LOAD) {
|
| duke@0 | // base address of a library is the lowest address of its loaded
|
| duke@0 | // segments.
|
| duke@0 | if (libbase == NULL || libbase > segbase) {
|
| duke@0 | libbase = segbase;
|
| duke@0 | }
|
| duke@0 | // see if 'addr' is within current segment
|
| duke@0 | if (segbase <= d->addr &&
|
| duke@0 | d->addr < segbase + info->dlpi_phdr[i].p_memsz) {
|
| duke@0 | found = true;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // dlpi_name is NULL or empty if the ELF file is executable, return 0
|
| duke@0 | // so dll_address_to_library_name() can fall through to use dladdr() which
|
| duke@0 | // can figure out executable name from argv[0].
|
| duke@0 | if (found && info->dlpi_name && info->dlpi_name[0]) {
|
| duke@0 | d->base = libbase;
|
| duke@0 | if (d->fname) {
|
| duke@0 | jio_snprintf(d->fname, d->buflen, "%s", info->dlpi_name);
|
| duke@0 | }
|
| duke@0 | return 1;
|
| duke@0 | }
|
| duke@0 | return 0;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | bool os::dll_address_to_library_name(address addr, char* buf,
|
| duke@0 | int buflen, int* offset) {
|
| duke@0 | Dl_info dlinfo;
|
| duke@0 | struct _address_to_library_name data;
|
| duke@0 |
|
| duke@0 | // There is a bug in old glibc dladdr() implementation that it could resolve
|
| duke@0 | // to wrong library name if the .so file has a base address != NULL. Here
|
| duke@0 | // we iterate through the program headers of all loaded libraries to find
|
| duke@0 | // out which library 'addr' really belongs to. This workaround can be
|
| duke@0 | // removed once the minimum requirement for glibc is moved to 2.3.x.
|
| duke@0 | data.addr = addr;
|
| duke@0 | data.fname = buf;
|
| duke@0 | data.buflen = buflen;
|
| duke@0 | data.base = NULL;
|
| duke@0 | int rslt = dl_iterate_phdr(address_to_library_name_callback, (void *)&data);
|
| duke@0 |
|
| duke@0 | if (rslt) {
|
| duke@0 | // buf already contains library name
|
| duke@0 | if (offset) *offset = addr - data.base;
|
| duke@0 | return true;
|
| duke@0 | } else if (dladdr((void*)addr, &dlinfo)){
|
| duke@0 | if (buf) jio_snprintf(buf, buflen, "%s", dlinfo.dli_fname);
|
| duke@0 | if (offset) *offset = addr - (address)dlinfo.dli_fbase;
|
| duke@0 | return true;
|
| duke@0 | } else {
|
| duke@0 | if (buf) buf[0] = '\0';
|
| duke@0 | if (offset) *offset = -1;
|
| duke@0 | return false;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Loads .dll/.so and
|
| duke@0 | // in case of error it checks if .dll/.so was built for the
|
| duke@0 | // same architecture as Hotspot is running on
|
| duke@0 |
|
| duke@0 | void * os::dll_load(const char *filename, char *ebuf, int ebuflen)
|
| duke@0 | {
|
| duke@0 | void * result= ::dlopen(filename, RTLD_LAZY);
|
| duke@0 | if (result != NULL) {
|
| duke@0 | // Successful loading
|
| duke@0 | return result;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | Elf32_Ehdr elf_head;
|
| duke@0 |
|
| duke@0 | // Read system error message into ebuf
|
| duke@0 | // It may or may not be overwritten below
|
| duke@0 | ::strncpy(ebuf, ::dlerror(), ebuflen-1);
|
| duke@0 | ebuf[ebuflen-1]='\0';
|
| duke@0 | int diag_msg_max_length=ebuflen-strlen(ebuf);
|
| duke@0 | char* diag_msg_buf=ebuf+strlen(ebuf);
|
| duke@0 |
|
| duke@0 | if (diag_msg_max_length==0) {
|
| duke@0 | // No more space in ebuf for additional diagnostics message
|
| duke@0 | return NULL;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 |
|
| duke@0 | int file_descriptor= ::open(filename, O_RDONLY | O_NONBLOCK);
|
| duke@0 |
|
| duke@0 | if (file_descriptor < 0) {
|
| duke@0 | // Can't open library, report dlerror() message
|
| duke@0 | return NULL;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | bool failed_to_read_elf_head=
|
| duke@0 | (sizeof(elf_head)!=
|
| duke@0 | (::read(file_descriptor, &elf_head,sizeof(elf_head)))) ;
|
| duke@0 |
|
| duke@0 | ::close(file_descriptor);
|
| duke@0 | if (failed_to_read_elf_head) {
|
| duke@0 | // file i/o error - report dlerror() msg
|
| duke@0 | return NULL;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | typedef struct {
|
| duke@0 | Elf32_Half code; // Actual value as defined in elf.h
|
| duke@0 | Elf32_Half compat_class; // Compatibility of archs at VM's sense
|
| duke@0 | char elf_class; // 32 or 64 bit
|
| duke@0 | char endianess; // MSB or LSB
|
| duke@0 | char* name; // String representation
|
| duke@0 | } arch_t;
|
| duke@0 |
|
| duke@0 | #ifndef EM_486
|
| duke@0 | #define EM_486 6 /* Intel 80486 */
|
| duke@0 | #endif
|
| duke@0 |
|
| duke@0 | static const arch_t arch_array[]={
|
| duke@0 | {EM_386, EM_386, ELFCLASS32, ELFDATA2LSB, (char*)"IA 32"},
|
| duke@0 | {EM_486, EM_386, ELFCLASS32, ELFDATA2LSB, (char*)"IA 32"},
|
| duke@0 | {EM_IA_64, EM_IA_64, ELFCLASS64, ELFDATA2LSB, (char*)"IA 64"},
|
| duke@0 | {EM_X86_64, EM_X86_64, ELFCLASS64, ELFDATA2LSB, (char*)"AMD 64"},
|
| duke@0 | {EM_SPARC, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"},
|
| duke@0 | {EM_SPARC32PLUS, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"},
|
| duke@0 | {EM_SPARCV9, EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, (char*)"Sparc v9 64"},
|
| duke@0 | {EM_PPC, EM_PPC, ELFCLASS32, ELFDATA2MSB, (char*)"Power PC 32"},
|
| never@1241 | {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"},
|
| never@1241 | {EM_ARM, EM_ARM, ELFCLASS32, ELFDATA2LSB, (char*)"ARM"},
|
| never@1241 | {EM_S390, EM_S390, ELFCLASSNONE, ELFDATA2MSB, (char*)"IBM System/390"},
|
| never@1241 | {EM_ALPHA, EM_ALPHA, ELFCLASS64, ELFDATA2LSB, (char*)"Alpha"},
|
| never@1241 | {EM_MIPS_RS3_LE, EM_MIPS_RS3_LE, ELFCLASS32, ELFDATA2LSB, (char*)"MIPSel"},
|
| never@1241 | {EM_MIPS, EM_MIPS, ELFCLASS32, ELFDATA2MSB, (char*)"MIPS"},
|
| never@1241 | {EM_PARISC, EM_PARISC, ELFCLASS32, ELFDATA2MSB, (char*)"PARISC"},
|
| never@1241 | {EM_68K, EM_68K, ELFCLASS32, ELFDATA2MSB, (char*)"M68k"}
|
| duke@0 | };
|
| duke@0 |
|
| duke@0 | #if (defined IA32)
|
| duke@0 | static Elf32_Half running_arch_code=EM_386;
|
| duke@0 | #elif (defined AMD64)
|
| duke@0 | static Elf32_Half running_arch_code=EM_X86_64;
|
| duke@0 | #elif (defined IA64)
|
| duke@0 | static Elf32_Half running_arch_code=EM_IA_64;
|
| duke@0 | #elif (defined __sparc) && (defined _LP64)
|
| duke@0 | static Elf32_Half running_arch_code=EM_SPARCV9;
|
| duke@0 | #elif (defined __sparc) && (!defined _LP64)
|
| duke@0 | static Elf32_Half running_arch_code=EM_SPARC;
|
| duke@0 | #elif (defined __powerpc64__)
|
| duke@0 | static Elf32_Half running_arch_code=EM_PPC64;
|
| duke@0 | #elif (defined __powerpc__)
|
| duke@0 | static Elf32_Half running_arch_code=EM_PPC;
|
| never@1241 | #elif (defined ARM)
|
| never@1241 | static Elf32_Half running_arch_code=EM_ARM;
|
| never@1241 | #elif (defined S390)
|
| never@1241 | static Elf32_Half running_arch_code=EM_S390;
|
| never@1241 | #elif (defined ALPHA)
|
| never@1241 | static Elf32_Half running_arch_code=EM_ALPHA;
|
| never@1241 | #elif (defined MIPSEL)
|
| never@1241 | static Elf32_Half running_arch_code=EM_MIPS_RS3_LE;
|
| never@1241 | #elif (defined PARISC)
|
| never@1241 | static Elf32_Half running_arch_code=EM_PARISC;
|
| never@1241 | #elif (defined MIPS)
|
| never@1241 | static Elf32_Half running_arch_code=EM_MIPS;
|
| never@1241 | #elif (defined M68K)
|
| never@1241 | static Elf32_Half running_arch_code=EM_68K;
|
| duke@0 | #else
|
| duke@0 | #error Method os::dll_load requires that one of following is defined:\
|
| never@1241 | IA32, AMD64, IA64, __sparc, __powerpc__, ARM, S390, ALPHA, MIPS, MIPSEL, PARISC, M68K
|
| duke@0 | #endif
|
| duke@0 |
|
| duke@0 | // Identify compatability class for VM's architecture and library's architecture
|
| duke@0 | // Obtain string descriptions for architectures
|
| duke@0 |
|
| duke@0 | arch_t lib_arch={elf_head.e_machine,0,elf_head.e_ident[EI_CLASS], elf_head.e_ident[EI_DATA], NULL};
|
| duke@0 | int running_arch_index=-1;
|
| duke@0 |
|
| duke@0 | for (unsigned int i=0 ; i < ARRAY_SIZE(arch_array) ; i++ ) {
|
| duke@0 | if (running_arch_code == arch_array[i].code) {
|
| duke@0 | running_arch_index = i;
|
| duke@0 | }
|
| duke@0 | if (lib_arch.code == arch_array[i].code) {
|
| duke@0 | lib_arch.compat_class = arch_array[i].compat_class;
|
| duke@0 | lib_arch.name = arch_array[i].name;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | assert(running_arch_index != -1,
|
| duke@0 | "Didn't find running architecture code (running_arch_code) in arch_array");
|
| duke@0 | if (running_arch_index == -1) {
|
| duke@0 | // Even though running architecture detection failed
|
| duke@0 | // we may still continue with reporting dlerror() message
|
| duke@0 | return NULL;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | if (lib_arch.endianess != arch_array[running_arch_index].endianess) {
|
| duke@0 | ::snprintf(diag_msg_buf, diag_msg_max_length-1," (Possible cause: endianness mismatch)");
|
| duke@0 | return NULL;
|
| duke@0 | }
|
| duke@0 |
|
| never@1241 | #ifndef S390
|
| duke@0 | if (lib_arch.elf_class != arch_array[running_arch_index].elf_class) {
|
| duke@0 | ::snprintf(diag_msg_buf, diag_msg_max_length-1," (Possible cause: architecture word width mismatch)");
|
| duke@0 | return NULL;
|
| duke@0 | }
|
| never@1241 | #endif // !S390
|
| duke@0 |
|
| duke@0 | if (lib_arch.compat_class != arch_array[running_arch_index].compat_class) {
|
| duke@0 | if ( lib_arch.name!=NULL ) {
|
| duke@0 | ::snprintf(diag_msg_buf, diag_msg_max_length-1,
|
| duke@0 | " (Possible cause: can't load %s-bit .so on a %s-bit platform)",
|
| duke@0 | lib_arch.name, arch_array[running_arch_index].name);
|
| duke@0 | } else {
|
| duke@0 | ::snprintf(diag_msg_buf, diag_msg_max_length-1,
|
| duke@0 | " (Possible cause: can't load this .so (machine code=0x%x) on a %s-bit platform)",
|
| duke@0 | lib_arch.code,
|
| duke@0 | arch_array[running_arch_index].name);
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | return NULL;
|
| duke@0 | }
|
| duke@0 |
|
| kamg@299 | /*
|
| kamg@299 | * glibc-2.0 libdl is not MT safe. If you are building with any glibc,
|
| kamg@299 | * chances are you might want to run the generated bits against glibc-2.0
|
| kamg@299 | * libdl.so, so always use locking for any version of glibc.
|
| kamg@299 | */
|
| kamg@299 | void* os::dll_lookup(void* handle, const char* name) {
|
| kamg@299 | pthread_mutex_lock(&dl_mutex);
|
| kamg@299 | void* res = dlsym(handle, name);
|
| kamg@299 | pthread_mutex_unlock(&dl_mutex);
|
| kamg@299 | return res;
|
| kamg@299 | }
|
| duke@0 |
|
| duke@0 |
|
| duke@0 | bool _print_ascii_file(const char* filename, outputStream* st) {
|
| duke@0 | int fd = open(filename, O_RDONLY);
|
| duke@0 | if (fd == -1) {
|
| duke@0 | return false;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | char buf[32];
|
| duke@0 | int bytes;
|
| duke@0 | while ((bytes = read(fd, buf, sizeof(buf))) > 0) {
|
| duke@0 | st->print_raw(buf, bytes);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | close(fd);
|
| duke@0 |
|
| duke@0 | return true;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | void os::print_dll_info(outputStream *st) {
|
| duke@0 | st->print_cr("Dynamic libraries:");
|
| duke@0 |
|
| duke@0 | char fname[32];
|
| duke@0 | pid_t pid = os::Linux::gettid();
|
| duke@0 |
|
| duke@0 | jio_snprintf(fname, sizeof(fname), "/proc/%d/maps", pid);
|
| duke@0 |
|
| duke@0 | if (!_print_ascii_file(fname, st)) {
|
| duke@0 | st->print("Can not get library information for pid = %d\n", pid);
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 |
|
| duke@0 | void os::print_os_info(outputStream* st) {
|
| duke@0 | st->print("OS:");
|
| duke@0 |
|
| duke@0 | // Try to identify popular distros.
|
| duke@0 | // Most Linux distributions have /etc/XXX-release file, which contains
|
| duke@0 | // the OS version string. Some have more than one /etc/XXX-release file
|
| duke@0 | // (e.g. Mandrake has both /etc/mandrake-release and /etc/redhat-release.),
|
| duke@0 | // so the order is important.
|
| duke@0 | if (!_print_ascii_file("/etc/mandrake-release", st) &&
|
| duke@0 | !_print_ascii_file("/etc/sun-release", st) &&
|
| duke@0 | !_print_ascii_file("/etc/redhat-release", st) &&
|
| duke@0 | !_print_ascii_file("/etc/SuSE-release", st) &&
|
| duke@0 | !_print_ascii_file("/etc/turbolinux-release", st) &&
|
| duke@0 | !_print_ascii_file("/etc/gentoo-release", st) &&
|
| bobv@1892 | !_print_ascii_file("/etc/debian_version", st) &&
|
| bobv@1892 | !_print_ascii_file("/etc/ltib-release", st) &&
|
| bobv@1892 | !_print_ascii_file("/etc/angstrom-version", st)) {
|
| duke@0 | st->print("Linux");
|
| duke@0 | }
|
| duke@0 | st->cr();
|
| duke@0 |
|
| duke@0 | // kernel
|
| duke@0 | st->print("uname:");
|
| duke@0 | struct utsname name;
|
| duke@0 | uname(&name);
|
| duke@0 | st->print(name.sysname); st->print(" ");
|
| duke@0 | st->print(name.release); st->print(" ");
|
| duke@0 | st->print(name.version); st->print(" ");
|
| duke@0 | st->print(name.machine);
|
| duke@0 | st->cr();
|
| duke@0 |
|
| duke@0 | // Print warning if unsafe chroot environment detected
|
| duke@0 | if (unsafe_chroot_detected) {
|
| duke@0 | st->print("WARNING!! ");
|
| duke@0 | st->print_cr(unstable_chroot_error);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // libc, pthread
|
| duke@0 | st->print("libc:");
|
| duke@0 | st->print(os::Linux::glibc_version()); st->print(" ");
|
| duke@0 | st->print(os::Linux::libpthread_version()); st->print(" ");
|
| duke@0 | if (os::Linux::is_LinuxThreads()) {
|
| duke@0 | st->print("(%s stack)", os::Linux::is_floating_stack() ? "floating" : "fixed");
|
| duke@0 | }
|
| duke@0 | st->cr();
|
| duke@0 |
|
| duke@0 | // rlimit
|
| duke@0 | st->print("rlimit:");
|
| duke@0 | struct rlimit rlim;
|
| duke@0 |
|
| duke@0 | st->print(" STACK ");
|
| duke@0 | getrlimit(RLIMIT_STACK, &rlim);
|
| duke@0 | if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity");
|
| duke@0 | else st->print("%uk", rlim.rlim_cur >> 10);
|
| duke@0 |
|
| duke@0 | st->print(", CORE ");
|
| duke@0 | getrlimit(RLIMIT_CORE, &rlim);
|
| duke@0 | if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity");
|
| duke@0 | else st->print("%uk", rlim.rlim_cur >> 10);
|
| duke@0 |
|
| duke@0 | st->print(", NPROC ");
|
| duke@0 | getrlimit(RLIMIT_NPROC, &rlim);
|
| duke@0 | if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity");
|
| duke@0 | else st->print("%d", rlim.rlim_cur);
|
| duke@0 |
|
| duke@0 | st->print(", NOFILE ");
|
| duke@0 | getrlimit(RLIMIT_NOFILE, &rlim);
|
| duke@0 | if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity");
|
| duke@0 | else st->print("%d", rlim.rlim_cur);
|
| duke@0 |
|
| duke@0 | st->print(", AS ");
|
| duke@0 | getrlimit(RLIMIT_AS, &rlim);
|
| duke@0 | if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity");
|
| duke@0 | else st->print("%uk", rlim.rlim_cur >> 10);
|
| duke@0 | st->cr();
|
| duke@0 |
|
| duke@0 | // load average
|
| duke@0 | st->print("load average:");
|
| duke@0 | double loadavg[3];
|
| duke@0 | os::loadavg(loadavg, 3);
|
| duke@0 | st->print("%0.02f %0.02f %0.02f", loadavg[0], loadavg[1], loadavg[2]);
|
| bobv@1892 | st->cr();
|
| bobv@1892 |
|
| bobv@1892 | // meminfo
|
| bobv@1892 | st->print("\n/proc/meminfo:\n");
|
| bobv@1892 | _print_ascii_file("/proc/meminfo", st);
|
| duke@0 | st->cr();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | void os::print_memory_info(outputStream* st) {
|
| duke@0 |
|
| duke@0 | st->print("Memory:");
|
| duke@0 | st->print(" %dk page", os::vm_page_size()>>10);
|
| duke@0 |
|
| duke@0 | // values in struct sysinfo are "unsigned long"
|
| duke@0 | struct sysinfo si;
|
| duke@0 | sysinfo(&si);
|
| duke@0 |
|
| duke@0 | st->print(", physical " UINT64_FORMAT "k",
|
| duke@0 | os::physical_memory() >> 10);
|
| duke@0 | st->print("(" UINT64_FORMAT "k free)",
|
| duke@0 | os::available_memory() >> 10);
|
| duke@0 | st->print(", swap " UINT64_FORMAT "k",
|
| duke@0 | ((jlong)si.totalswap * si.mem_unit) >> 10);
|
| duke@0 | st->print("(" UINT64_FORMAT "k free)",
|
| duke@0 | ((jlong)si.freeswap * si.mem_unit) >> 10);
|
| duke@0 | st->cr();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Taken from /usr/include/bits/siginfo.h Supposed to be architecture specific
|
| duke@0 | // but they're the same for all the linux arch that we support
|
| duke@0 | // and they're the same for solaris but there's no common place to put this.
|
| duke@0 | const char *ill_names[] = { "ILL0", "ILL_ILLOPC", "ILL_ILLOPN", "ILL_ILLADR",
|
| duke@0 | "ILL_ILLTRP", "ILL_PRVOPC", "ILL_PRVREG",
|
| duke@0 | "ILL_COPROC", "ILL_BADSTK" };
|
| duke@0 |
|
| duke@0 | const char *fpe_names[] = { "FPE0", "FPE_INTDIV", "FPE_INTOVF", "FPE_FLTDIV",
|
| duke@0 | "FPE_FLTOVF", "FPE_FLTUND", "FPE_FLTRES",
|
| duke@0 | "FPE_FLTINV", "FPE_FLTSUB", "FPE_FLTDEN" };
|
| duke@0 |
|
| duke@0 | const char *segv_names[] = { "SEGV0", "SEGV_MAPERR", "SEGV_ACCERR" };
|
| duke@0 |
|
| duke@0 | const char *bus_names[] = { "BUS0", "BUS_ADRALN", "BUS_ADRERR", "BUS_OBJERR" };
|
| duke@0 |
|
| duke@0 | void os::print_siginfo(outputStream* st, void* siginfo) {
|
| duke@0 | st->print("siginfo:");
|
| duke@0 |
|
| duke@0 | const int buflen = 100;
|
| duke@0 | char buf[buflen];
|
| duke@0 | siginfo_t *si = (siginfo_t*)siginfo;
|
| duke@0 | st->print("si_signo=%s: ", os::exception_name(si->si_signo, buf, buflen));
|
| duke@0 | if (si->si_errno != 0 && strerror_r(si->si_errno, buf, buflen) == 0) {
|
| duke@0 | st->print("si_errno=%s", buf);
|
| duke@0 | } else {
|
| duke@0 | st->print("si_errno=%d", si->si_errno);
|
| duke@0 | }
|
| duke@0 | const int c = si->si_code;
|
| duke@0 | assert(c > 0, "unexpected si_code");
|
| duke@0 | switch (si->si_signo) {
|
| duke@0 | case SIGILL:
|
| duke@0 | st->print(", si_code=%d (%s)", c, c > 8 ? "" : ill_names[c]);
|
| duke@0 | st->print(", si_addr=" PTR_FORMAT, si->si_addr);
|
| duke@0 | break;
|
| duke@0 | case SIGFPE:
|
| duke@0 | st->print(", si_code=%d (%s)", c, c > 9 ? "" : fpe_names[c]);
|
| duke@0 | st->print(", si_addr=" PTR_FORMAT, si->si_addr);
|
| duke@0 | break;
|
| duke@0 | case SIGSEGV:
|
| duke@0 | st->print(", si_code=%d (%s)", c, c > 2 ? "" : segv_names[c]);
|
| duke@0 | st->print(", si_addr=" PTR_FORMAT, si->si_addr);
|
| duke@0 | break;
|
| duke@0 | case SIGBUS:
|
| duke@0 | st->print(", si_code=%d (%s)", c, c > 3 ? "" : bus_names[c]);
|
| duke@0 | st->print(", si_addr=" PTR_FORMAT, si->si_addr);
|
| duke@0 | break;
|
| duke@0 | default:
|
| duke@0 | st->print(", si_code=%d", si->si_code);
|
| duke@0 | // no si_addr
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | if ((si->si_signo == SIGBUS || si->si_signo == SIGSEGV) &&
|
| duke@0 | UseSharedSpaces) {
|
| duke@0 | FileMapInfo* mapinfo = FileMapInfo::current_info();
|
| duke@0 | if (mapinfo->is_in_shared_space(si->si_addr)) {
|
| duke@0 | st->print("\n\nError accessing class data sharing archive." \
|
| duke@0 | " Mapped file inaccessible during execution, " \
|
| duke@0 | " possible disk/network problem.");
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | st->cr();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 |
|
| duke@0 | static void print_signal_handler(outputStream* st, int sig,
|
| duke@0 | char* buf, size_t buflen);
|
| duke@0 |
|
| duke@0 | void os::print_signal_handlers(outputStream* st, char* buf, size_t buflen) {
|
| duke@0 | st->print_cr("Signal Handlers:");
|
| duke@0 | print_signal_handler(st, SIGSEGV, buf, buflen);
|
| duke@0 | print_signal_handler(st, SIGBUS , buf, buflen);
|
| duke@0 | print_signal_handler(st, SIGFPE , buf, buflen);
|
| duke@0 | print_signal_handler(st, SIGPIPE, buf, buflen);
|
| duke@0 | print_signal_handler(st, SIGXFSZ, buf, buflen);
|
| duke@0 | print_signal_handler(st, SIGILL , buf, buflen);
|
| duke@0 | print_signal_handler(st, INTERRUPT_SIGNAL, buf, buflen);
|
| duke@0 | print_signal_handler(st, SR_signum, buf, buflen);
|
| duke@0 | print_signal_handler(st, SHUTDOWN1_SIGNAL, buf, buflen);
|
| duke@0 | print_signal_handler(st, SHUTDOWN2_SIGNAL , buf, buflen);
|
| duke@0 | print_signal_handler(st, SHUTDOWN3_SIGNAL , buf, buflen);
|
| duke@0 | print_signal_handler(st, BREAK_SIGNAL, buf, buflen);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | static char saved_jvm_path[MAXPATHLEN] = {0};
|
| duke@0 |
|
| duke@0 | // Find the full path to the current module, libjvm.so or libjvm_g.so
|
| mchung@1839 | void os::jvm_path(char *buf, jint buflen) {
|
| duke@0 | // Error checking.
|
| mchung@1839 | if (buflen < MAXPATHLEN) {
|
| duke@0 | assert(false, "must use a large-enough buffer");
|
| duke@0 | buf[0] = '\0';
|
| duke@0 | return;
|
| duke@0 | }
|
| duke@0 | // Lazy resolve the path to current module.
|
| duke@0 | if (saved_jvm_path[0] != 0) {
|
| duke@0 | strcpy(buf, saved_jvm_path);
|
| duke@0 | return;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | char dli_fname[MAXPATHLEN];
|
| duke@0 | bool ret = dll_address_to_library_name(
|
| duke@0 | CAST_FROM_FN_PTR(address, os::jvm_path),
|
| duke@0 | dli_fname, sizeof(dli_fname), NULL);
|
| duke@0 | assert(ret != 0, "cannot locate libjvm");
|
| bobv@1892 | char *rp = realpath(dli_fname, buf);
|
| bobv@1892 | if (rp == NULL)
|
| xlu@643 | return;
|
| duke@0 |
|
| duke@0 | if (strcmp(Arguments::sun_java_launcher(), "gamma") == 0) {
|
| duke@0 | // Support for the gamma launcher. Typical value for buf is
|
| duke@0 | // "<JAVA_HOME>/jre/lib/<arch>/<vmtype>/libjvm.so". If "/jre/lib/" appears at
|
| duke@0 | // the right place in the string, then assume we are installed in a JDK and
|
| duke@0 | // we're done. Otherwise, check for a JAVA_HOME environment variable and fix
|
| duke@0 | // up the path so it looks like libjvm.so is installed there (append a
|
| duke@0 | // fake suffix hotspot/libjvm.so).
|
| duke@0 | const char *p = buf + strlen(buf) - 1;
|
| duke@0 | for (int count = 0; p > buf && count < 5; ++count) {
|
| duke@0 | for (--p; p > buf && *p != '/'; --p)
|
| duke@0 | /* empty */ ;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | if (strncmp(p, "/jre/lib/", 9) != 0) {
|
| duke@0 | // Look for JAVA_HOME in the environment.
|
| duke@0 | char* java_home_var = ::getenv("JAVA_HOME");
|
| duke@0 | if (java_home_var != NULL && java_home_var[0] != 0) {
|
| mchung@1839 | char* jrelib_p;
|
| mchung@1839 | int len;
|
| mchung@1839 |
|
| duke@0 | // Check the current module name "libjvm.so" or "libjvm_g.so".
|
| duke@0 | p = strrchr(buf, '/');
|
| duke@0 | assert(strstr(p, "/libjvm") == p, "invalid library name");
|
| duke@0 | p = strstr(p, "_g") ? "_g" : "";
|
| duke@0 |
|
| bobv@1892 | rp = realpath(java_home_var, buf);
|
| bobv@1892 | if (rp == NULL)
|
| xlu@643 | return;
|
| mchung@1839 |
|
| mchung@1839 | // determine if this is a legacy image or modules image
|
| mchung@1839 | // modules image doesn't have "jre" subdirectory
|
| mchung@1839 | len = strlen(buf);
|
| mchung@1839 | jrelib_p = buf + len;
|
| mchung@1839 | snprintf(jrelib_p, buflen-len, "/jre/lib/%s", cpu_arch);
|
| mchung@1839 | if (0 != access(buf, F_OK)) {
|
| mchung@1839 | snprintf(jrelib_p, buflen-len, "/lib/%s", cpu_arch);
|
| mchung@1839 | }
|
| mchung@1839 |
|
| duke@0 | if (0 == access(buf, F_OK)) {
|
| duke@0 | // Use current module name "libjvm[_g].so" instead of
|
| duke@0 | // "libjvm"debug_only("_g")".so" since for fastdebug version
|
| duke@0 | // we should have "libjvm.so" but debug_only("_g") adds "_g"!
|
| duke@0 | // It is used when we are choosing the HPI library's name
|
| duke@0 | // "libhpi[_g].so" in hpi::initialize_get_interface().
|
| mchung@1839 | len = strlen(buf);
|
| mchung@1839 | snprintf(buf + len, buflen-len, "/hotspot/libjvm%s.so", p);
|
| duke@0 | } else {
|
| duke@0 | // Go back to path of .so
|
| bobv@1892 | rp = realpath(dli_fname, buf);
|
| bobv@1892 | if (rp == NULL)
|
| xlu@643 | return;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | strcpy(saved_jvm_path, buf);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | void os::print_jni_name_prefix_on(outputStream* st, int args_size) {
|
| duke@0 | // no prefix required, not even "_"
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | void os::print_jni_name_suffix_on(outputStream* st, int args_size) {
|
| duke@0 | // no suffix required
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | ////////////////////////////////////////////////////////////////////////////////
|
| duke@0 | // sun.misc.Signal support
|
| duke@0 |
|
| duke@0 | static volatile jint sigint_count = 0;
|
| duke@0 |
|
| duke@0 | static void
|
| duke@0 | UserHandler(int sig, void *siginfo, void *context) {
|
| duke@0 | // 4511530 - sem_post is serialized and handled by the manager thread. When
|
| duke@0 | // the program is interrupted by Ctrl-C, SIGINT is sent to every thread. We
|
| duke@0 | // don't want to flood the manager thread with sem_post requests.
|
| duke@0 | if (sig == SIGINT && Atomic::add(1, &sigint_count) > 1)
|
| duke@0 | return;
|
| duke@0 |
|
| duke@0 | // Ctrl-C is pressed during error reporting, likely because the error
|
| duke@0 | // handler fails to abort. Let VM die immediately.
|
| duke@0 | if (sig == SIGINT && is_error_reported()) {
|
| duke@0 | os::die();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | os::signal_notify(sig);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | void* os::user_handler() {
|
| duke@0 | return CAST_FROM_FN_PTR(void*, UserHandler);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | extern "C" {
|
| duke@0 | typedef void (*sa_handler_t)(int);
|
| duke@0 | typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | void* os::signal(int signal_number, void* handler) {
|
| duke@0 | struct sigaction sigAct, oldSigAct;
|
| duke@0 |
|
| duke@0 | sigfillset(&(sigAct.sa_mask));
|
| duke@0 | sigAct.sa_flags = SA_RESTART|SA_SIGINFO;
|
| duke@0 | sigAct.sa_handler = CAST_TO_FN_PTR(sa_handler_t, handler);
|
| duke@0 |
|
| duke@0 | if (sigaction(signal_number, &sigAct, &oldSigAct)) {
|
| duke@0 | // -1 means registration failed
|
| duke@0 | return (void *)-1;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | return CAST_FROM_FN_PTR(void*, oldSigAct.sa_handler);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | void os::signal_raise(int signal_number) {
|
| duke@0 | ::raise(signal_number);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | /*
|
| duke@0 | * The following code is moved from os.cpp for making this
|
| duke@0 | * code platform specific, which it is by its very nature.
|
| duke@0 | */
|
| duke@0 |
|
| duke@0 | // Will be modified when max signal is changed to be dynamic
|
| duke@0 | int os::sigexitnum_pd() {
|
| duke@0 | return NSIG;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // a counter for each possible signal value
|
| duke@0 | static volatile jint pending_signals[NSIG+1] = { 0 };
|
| duke@0 |
|
| duke@0 | // Linux(POSIX) specific hand shaking semaphore.
|
| duke@0 | static sem_t sig_sem;
|
| duke@0 |
|
| duke@0 | void os::signal_init_pd() {
|
| duke@0 | // Initialize signal structures
|
| duke@0 | ::memset((void*)pending_signals, 0, sizeof(pending_signals));
|
| duke@0 |
|
| duke@0 | // Initialize signal semaphore
|
| duke@0 | ::sem_init(&sig_sem, 0, 0);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | void os::signal_notify(int sig) {
|
| duke@0 | Atomic::inc(&pending_signals[sig]);
|
| duke@0 | ::sem_post(&sig_sem);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | static int check_pending_signals(bool wait) {
|
| duke@0 | Atomic::store(0, &sigint_count);
|
| duke@0 | for (;;) {
|
| duke@0 | for (int i = 0; i < NSIG + 1; i++) {
|
| duke@0 | jint n = pending_signals[i];
|
| duke@0 | if (n > 0 && n == Atomic::cmpxchg(n - 1, &pending_signals[i], n)) {
|
| duke@0 | return i;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | if (!wait) {
|
| duke@0 | return -1;
|
| duke@0 | }
|
| duke@0 | JavaThread *thread = JavaThread::current();
|
| duke@0 | ThreadBlockInVM tbivm(thread);
|
| duke@0 |
|
| duke@0 | bool threadIsSuspended;
|
| duke@0 | do {
|
| duke@0 | thread->set_suspend_equivalent();
|
| duke@0 | // cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
|
| duke@0 | ::sem_wait(&sig_sem);
|
| duke@0 |
|
| duke@0 | // were we externally suspended while we were waiting?
|
| duke@0 | threadIsSuspended = thread->handle_special_suspend_equivalent_condition();
|
| duke@0 | if (threadIsSuspended) {
|
| duke@0 | //
|
| duke@0 | // The semaphore has been incremented, but while we were waiting
|
| duke@0 | // another thread suspended us. We don't want to continue running
|
| duke@0 | // while suspended because that would surprise the thread that
|
| duke@0 | // suspended us.
|
| duke@0 | //
|
| duke@0 | ::sem_post(&sig_sem);
|
| duke@0 |
|
| duke@0 | thread->java_suspend_self();
|
| duke@0 | }
|
| duke@0 | } while (threadIsSuspended);
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | int os::signal_lookup() {
|
| duke@0 | return check_pending_signals(false);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | int os::signal_wait() {
|
| duke@0 | return check_pending_signals(true);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | ////////////////////////////////////////////////////////////////////////////////
|
| duke@0 | // Virtual Memory
|
| duke@0 |
|
| duke@0 | int os::vm_page_size() {
|
| duke@0 | // Seems redundant as all get out
|
| duke@0 | assert(os::Linux::page_size() != -1, "must call os::init");
|
| duke@0 | return os::Linux::page_size();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Solaris allocates memory by pages.
|
| duke@0 | int os::vm_allocation_granularity() {
|
| duke@0 | assert(os::Linux::page_size() != -1, "must call os::init");
|
| duke@0 | return os::Linux::page_size();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Rationale behind this function:
|
| duke@0 | // current (Mon Apr 25 20:12:18 MSD 2005) oprofile drops samples without executable
|
| duke@0 | // mapping for address (see lookup_dcookie() in the kernel module), thus we cannot get
|
| duke@0 | // samples for JITted code. Here we create private executable mapping over the code cache
|
| duke@0 | // and then we can use standard (well, almost, as mapping can change) way to provide
|
| duke@0 | // info for the reporting script by storing timestamp and location of symbol
|
| duke@0 | void linux_wrap_code(char* base, size_t size) {
|
| duke@0 | static volatile jint cnt = 0;
|
| duke@0 |
|
| duke@0 | if (!UseOprofile) {
|
| duke@0 | return;
|
| duke@0 | }
|
| duke@0 |
|
| coleenp@1714 | char buf[PATH_MAX+1];
|
| duke@0 | int num = Atomic::add(1, &cnt);
|
| duke@0 |
|
| coleenp@1648 | snprintf(buf, sizeof(buf), "%s/hs-vm-%d-%d",
|
| coleenp@1648 | os::get_temp_directory(), os::current_process_id(), num);
|
| duke@0 | unlink(buf);
|
| duke@0 |
|
| duke@0 | int fd = open(buf, O_CREAT | O_RDWR, S_IRWXU);
|
| duke@0 |
|
| duke@0 | if (fd != -1) {
|
| duke@0 | off_t rv = lseek(fd, size-2, SEEK_SET);
|
| duke@0 | if (rv != (off_t)-1) {
|
| duke@0 | if (write(fd, "", 1) == 1) {
|
| duke@0 | mmap(base, size,
|
| duke@0 | PROT_READ|PROT_WRITE|PROT_EXEC,
|
| duke@0 | MAP_PRIVATE|MAP_FIXED|MAP_NORESERVE, fd, 0);
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | close(fd);
|
| duke@0 | unlink(buf);
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // NOTE: Linux kernel does not really reserve the pages for us.
|
| duke@0 | // All it does is to check if there are enough free pages
|
| duke@0 | // left at the time of mmap(). This could be a potential
|
| duke@0 | // problem.
|
| coleenp@783 | bool os::commit_memory(char* addr, size_t size, bool exec) {
|
| coleenp@783 | int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
|
| coleenp@783 | uintptr_t res = (uintptr_t) ::mmap(addr, size, prot,
|
| duke@0 | MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0);
|
| duke@0 | return res != (uintptr_t) MAP_FAILED;
|
| duke@0 | }
|
| duke@0 |
|
| coleenp@783 | bool os::commit_memory(char* addr, size_t size, size_t alignment_hint,
|
| coleenp@783 | bool exec) {
|
| coleenp@783 | return commit_memory(addr, size, exec);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | void os::realign_memory(char *addr, size_t bytes, size_t alignment_hint) { }
|
| iveresov@198 |
|
| iveresov@198 | void os::free_memory(char *addr, size_t bytes) {
|
| iveresov@888 | ::mmap(addr, bytes, PROT_READ | PROT_WRITE,
|
| iveresov@888 | MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0);
|
| iveresov@198 | }
|
| iveresov@198 |
|
| iveresov@520 | void os::numa_make_global(char *addr, size_t bytes) {
|
| iveresov@520 | Linux::numa_interleave_memory(addr, bytes);
|
| iveresov@520 | }
|
| iveresov@198 |
|
| iveresov@198 | void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) {
|
| iveresov@198 | Linux::numa_tonode_memory(addr, bytes, lgrp_hint);
|
| iveresov@198 | }
|
| iveresov@198 |
|
| iveresov@198 | bool os::numa_topology_changed() { return false; }
|
| iveresov@198 |
|
| iveresov@198 | size_t os::numa_get_groups_num() {
|
| iveresov@198 | int max_node = Linux::numa_max_node();
|
| iveresov@198 | return max_node > 0 ? max_node + 1 : 1;
|
| iveresov@198 | }
|
| iveresov@198 |
|
| iveresov@198 | int os::numa_get_group_id() {
|
| iveresov@198 | int cpu_id = Linux::sched_getcpu();
|
| iveresov@198 | if (cpu_id != -1) {
|
| iveresov@198 | int lgrp_id = Linux::get_node_by_cpu(cpu_id);
|
| iveresov@198 | if (lgrp_id != -1) {
|
| iveresov@198 | return lgrp_id;
|
| iveresov@198 | }
|
| iveresov@198 | }
|
| iveresov@198 | return 0;
|
| iveresov@198 | }
|
| iveresov@198 |
|
| duke@0 | size_t os::numa_get_leaf_groups(int *ids, size_t size) {
|
| iveresov@198 | for (size_t i = 0; i < size; i++) {
|
| iveresov@198 | ids[i] = i;
|
| iveresov@198 | }
|
| iveresov@198 | return size;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | bool os::get_page_info(char *start, page_info* info) {
|
| duke@0 | return false;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | char *os::scan_pages(char *start, char* end, page_info* page_expected, page_info* page_found) {
|
| duke@0 | return end;
|
| duke@0 | }
|
| iveresov@198 |
|
| iveresov@198 | extern "C" void numa_warn(int number, char *where, ...) { }
|
| iveresov@198 | extern "C" void numa_error(char *where) { }
|
| iveresov@198 |
|
| iveresov@890 |
|
| iveresov@890 | // If we are running with libnuma version > 2, then we should
|
| iveresov@890 | // be trying to use symbols with versions 1.1
|
| iveresov@890 | // If we are running with earlier version, which did not have symbol versions,
|
| iveresov@890 | // we should use the base version.
|
| iveresov@890 | void* os::Linux::libnuma_dlsym(void* handle, const char *name) {
|
| iveresov@890 | void *f = dlvsym(handle, name, "libnuma_1.1");
|
| iveresov@890 | if (f == NULL) {
|
| iveresov@890 | f = dlsym(handle, name);
|
| iveresov@890 | }
|
| iveresov@890 | return f;
|
| iveresov@890 | }
|
| iveresov@890 |
|
| iveresov@520 | bool os::Linux::libnuma_init() {
|
| iveresov@198 | // sched_getcpu() should be in libc.
|
| iveresov@198 | set_sched_getcpu(CAST_TO_FN_PTR(sched_getcpu_func_t,
|
| iveresov@198 | dlsym(RTLD_DEFAULT, "sched_getcpu")));
|
| iveresov@198 |
|
| iveresov@198 | if (sched_getcpu() != -1) { // Does it work?
|
| iveresov@324 | void *handle = dlopen("libnuma.so.1", RTLD_LAZY);
|
| iveresov@198 | if (handle != NULL) {
|
| iveresov@198 | set_numa_node_to_cpus(CAST_TO_FN_PTR(numa_node_to_cpus_func_t,
|
| iveresov@890 | libnuma_dlsym(handle, "numa_node_to_cpus")));
|
| iveresov@198 | set_numa_max_node(CAST_TO_FN_PTR(numa_max_node_func_t,
|
| iveresov@890 | libnuma_dlsym(handle, "numa_max_node")));
|
| iveresov@198 | set_numa_available(CAST_TO_FN_PTR(numa_available_func_t,
|
| iveresov@890 | libnuma_dlsym(handle, "numa_available")));
|
| iveresov@198 | set_numa_tonode_memory(CAST_TO_FN_PTR(numa_tonode_memory_func_t,
|
| iveresov@890 | libnuma_dlsym(handle, "numa_tonode_memory")));
|
| iveresov@520 | set_numa_interleave_memory(CAST_TO_FN_PTR(numa_interleave_memory_func_t,
|
| iveresov@890 | libnuma_dlsym(handle, "numa_interleave_memory")));
|
| iveresov@520 |
|
| iveresov@520 |
|
| iveresov@198 | if (numa_available() != -1) {
|
| iveresov@890 | set_numa_all_nodes((unsigned long*)libnuma_dlsym(handle, "numa_all_nodes"));
|
| iveresov@198 | // Create a cpu -> node mapping
|
| iveresov@198 | _cpu_to_node = new (ResourceObj::C_HEAP) GrowableArray<int>(0, true);
|
| iveresov@198 | rebuild_cpu_to_node_map();
|
| iveresov@520 | return true;
|
| iveresov@198 | }
|
| iveresov@198 | }
|
| iveresov@198 | }
|
| iveresov@520 | return false;
|
| iveresov@198 | }
|
| iveresov@198 |
|
| iveresov@198 | // rebuild_cpu_to_node_map() constructs a table mapping cpud id to node id.
|
| iveresov@198 | // The table is later used in get_node_by_cpu().
|
| iveresov@198 | void os::Linux::rebuild_cpu_to_node_map() {
|
| iveresov@520 | const size_t NCPUS = 32768; // Since the buffer size computation is very obscure
|
| iveresov@520 | // in libnuma (possible values are starting from 16,
|
| iveresov@520 | // and continuing up with every other power of 2, but less
|
| iveresov@520 | // than the maximum number of CPUs supported by kernel), and
|
| iveresov@520 | // is a subject to change (in libnuma version 2 the requirements
|
| iveresov@520 | // are more reasonable) we'll just hardcode the number they use
|
| iveresov@520 | // in the library.
|
| iveresov@520 | const size_t BitsPerCLong = sizeof(long) * CHAR_BIT;
|
| iveresov@520 |
|
| iveresov@520 | size_t cpu_num = os::active_processor_count();
|
| iveresov@520 | size_t cpu_map_size = NCPUS / BitsPerCLong;
|
| iveresov@520 | size_t cpu_map_valid_size =
|
| iveresov@520 | MIN2((cpu_num + BitsPerCLong - 1) / BitsPerCLong, cpu_map_size);
|
| iveresov@520 |
|
| iveresov@198 | cpu_to_node()->clear();
|
| iveresov@198 | cpu_to_node()->at_grow(cpu_num - 1);
|
| iveresov@520 | size_t node_num = numa_get_groups_num();
|
| iveresov@520 |
|
| iveresov@198 | unsigned long *cpu_map = NEW_C_HEAP_ARRAY(unsigned long, cpu_map_size);
|
| iveresov@520 | for (size_t i = 0; i < node_num; i++) {
|
| iveresov@198 | if (numa_node_to_cpus(i, cpu_map, cpu_map_size * sizeof(unsigned long)) != -1) {
|
| iveresov@520 | for (size_t j = 0; j < cpu_map_valid_size; j++) {
|
| iveresov@198 | if (cpu_map[j] != 0) {
|
| iveresov@520 | for (size_t k = 0; k < BitsPerCLong; k++) {
|
| iveresov@198 | if (cpu_map[j] & (1UL << k)) {
|
| iveresov@520 | cpu_to_node()->at_put(j * BitsPerCLong + k, i);
|
| iveresov@198 | }
|
| iveresov@198 | }
|
| iveresov@198 | }
|
| iveresov@198 | }
|
| iveresov@198 | }
|
| iveresov@198 | }
|
| iveresov@198 | FREE_C_HEAP_ARRAY(unsigned long, cpu_map);
|
| iveresov@198 | }
|
| iveresov@198 |
|
| iveresov@198 | int os::Linux::get_node_by_cpu(int cpu_id) {
|
| iveresov@198 | if (cpu_to_node() != NULL && cpu_id >= 0 && cpu_id < cpu_to_node()->length()) {
|
| iveresov@198 | return cpu_to_node()->at(cpu_id);
|
| iveresov@198 | }
|
| iveresov@198 | return -1;
|
| iveresov@198 | }
|
| iveresov@198 |
|
| iveresov@198 | GrowableArray<int>* os::Linux::_cpu_to_node;
|
| iveresov@198 | os::Linux::sched_getcpu_func_t os::Linux::_sched_getcpu;
|
| iveresov@198 | os::Linux::numa_node_to_cpus_func_t os::Linux::_numa_node_to_cpus;
|
| iveresov@198 | os::Linux::numa_max_node_func_t os::Linux::_numa_max_node;
|
| iveresov@198 | os::Linux::numa_available_func_t os::Linux::_numa_available;
|
| iveresov@198 | os::Linux::numa_tonode_memory_func_t os::Linux::_numa_tonode_memory;
|
| iveresov@520 | os::Linux::numa_interleave_memory_func_t os::Linux::_numa_interleave_memory;
|
| iveresov@520 | unsigned long* os::Linux::_numa_all_nodes;
|
| duke@0 |
|
| duke@0 | bool os::uncommit_memory(char* addr, size_t size) {
|
| bobv@1892 | uintptr_t res = (uintptr_t) ::mmap(addr, size, PROT_NONE,
|
| bobv@1892 | MAP_PRIVATE|MAP_FIXED|MAP_NORESERVE|MAP_ANONYMOUS, -1, 0);
|
| bobv@1892 | return res != (uintptr_t) MAP_FAILED;
|
| coleenp@1621 | }
|
| coleenp@1621 |
|
| coleenp@1621 | // Linux uses a growable mapping for the stack, and if the mapping for
|
| coleenp@1621 | // the stack guard pages is not removed when we detach a thread the
|
| coleenp@1621 | // stack cannot grow beyond the pages where the stack guard was
|
| coleenp@1621 | // mapped. If at some point later in the process the stack expands to
|
| coleenp@1621 | // that point, the Linux kernel cannot expand the stack any further
|
| coleenp@1621 | // because the guard pages are in the way, and a segfault occurs.
|
| coleenp@1621 | //
|
| coleenp@1621 | // However, it's essential not to split the stack region by unmapping
|
| coleenp@1621 | // a region (leaving a hole) that's already part of the stack mapping,
|
| coleenp@1621 | // so if the stack mapping has already grown beyond the guard pages at
|
| coleenp@1621 | // the time we create them, we have to truncate the stack mapping.
|
| coleenp@1621 | // So, we need to know the extent of the stack mapping when
|
| coleenp@1621 | // create_stack_guard_pages() is called.
|
| coleenp@1621 |
|
| coleenp@1621 | // Find the bounds of the stack mapping. Return true for success.
|
| coleenp@1621 | //
|
| coleenp@1621 | // We only need this for stacks that are growable: at the time of
|
| coleenp@1621 | // writing thread stacks don't use growable mappings (i.e. those
|
| coleenp@1621 | // creeated with MAP_GROWSDOWN), and aren't marked "[stack]", so this
|
| coleenp@1621 | // only applies to the main thread.
|
| coleenp@1621 | static bool
|
| coleenp@1621 | get_stack_bounds(uintptr_t *bottom, uintptr_t *top)
|
| coleenp@1621 | {
|
| coleenp@1621 | FILE *f = fopen("/proc/self/maps", "r");
|
| coleenp@1621 | if (f == NULL)
|
| coleenp@1621 | return false;
|
| coleenp@1621 |
|
| coleenp@1621 | while (!feof(f)) {
|
| coleenp@1621 | size_t dummy;
|
| coleenp@1621 | char *str = NULL;
|
| coleenp@1621 | ssize_t len = getline(&str, &dummy, f);
|
| coleenp@1621 | if (len == -1) {
|
| coleenp@1626 | fclose(f);
|
| coleenp@1621 | return false;
|
| coleenp@1621 | }
|
| coleenp@1621 |
|
| coleenp@1621 | if (len > 0 && str[len-1] == '\n') {
|
| coleenp@1621 | str[len-1] = 0;
|
| coleenp@1621 | len--;
|
| coleenp@1621 | }
|
| coleenp@1621 |
|
| coleenp@1621 | static const char *stack_str = "[stack]";
|
| coleenp@1621 | if (len > (ssize_t)strlen(stack_str)
|
| coleenp@1621 | && (strcmp(str + len - strlen(stack_str), stack_str) == 0)) {
|
| coleenp@1621 | if (sscanf(str, "%" SCNxPTR "-%" SCNxPTR, bottom, top) == 2) {
|
| coleenp@1621 | uintptr_t sp = (uintptr_t)__builtin_frame_address(0);
|
| coleenp@1621 | if (sp >= *bottom && sp <= *top) {
|
| coleenp@1621 | free(str);
|
| coleenp@1626 | fclose(f);
|
| coleenp@1621 | return true;
|
| coleenp@1621 | }
|
| coleenp@1621 | }
|
| coleenp@1621 | }
|
| coleenp@1621 | free(str);
|
| coleenp@1621 | }
|
| coleenp@1626 | fclose(f);
|
| coleenp@1621 | return false;
|
| coleenp@1621 | }
|
| coleenp@1621 |
|
| coleenp@1621 | // If the (growable) stack mapping already extends beyond the point
|
| coleenp@1621 | // where we're going to put our guard pages, truncate the mapping at
|
| coleenp@1621 | // that point by munmap()ping it. This ensures that when we later
|
| coleenp@1621 | // munmap() the guard pages we don't leave a hole in the stack
|
| dholmes@1968 | // mapping. This only affects the main/initial thread, but guard
|
| dholmes@1968 | // against future OS changes
|
| coleenp@1621 | bool os::create_stack_guard_pages(char* addr, size_t size) {
|
| coleenp@1621 | uintptr_t stack_extent, stack_base;
|
| dholmes@1968 | bool chk_bounds = NOT_DEBUG(os::Linux::is_initial_thread()) DEBUG_ONLY(true);
|
| dholmes@1968 | if (chk_bounds && get_stack_bounds(&stack_extent, &stack_base)) {
|
| dholmes@1968 | assert(os::Linux::is_initial_thread(),
|
| dholmes@1968 | "growable stack in non-initial thread");
|
| coleenp@1621 | if (stack_extent < (uintptr_t)addr)
|
| coleenp@1621 | ::munmap((void*)stack_extent, (uintptr_t)addr - stack_extent);
|
| coleenp@1621 | }
|
| coleenp@1621 |
|
| coleenp@1621 | return os::commit_memory(addr, size);
|
| coleenp@1621 | }
|
| coleenp@1621 |
|
| coleenp@1621 | // If this is a growable mapping, remove the guard pages entirely by
|
| dholmes@1968 | // munmap()ping them. If not, just call uncommit_memory(). This only
|
| dholmes@1968 | // affects the main/initial thread, but guard against future OS changes
|
| coleenp@1621 | bool os::remove_stack_guard_pages(char* addr, size_t size) {
|
| coleenp@1621 | uintptr_t stack_extent, stack_base;
|
| dholmes@1968 | bool chk_bounds = NOT_DEBUG(os::Linux::is_initial_thread()) DEBUG_ONLY(true);
|
| dholmes@1968 | if (chk_bounds && get_stack_bounds(&stack_extent, &stack_base)) {
|
| dholmes@1968 | assert(os::Linux::is_initial_thread(),
|
| dholmes@1968 | "growable stack in non-initial thread");
|
| dholmes@1968 |
|
| coleenp@1621 | return ::munmap(addr, size) == 0;
|
| coleenp@1621 | }
|
| coleenp@1621 |
|
| coleenp@1621 | return os::uncommit_memory(addr, size);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | static address _highest_vm_reserved_address = NULL;
|
| duke@0 |
|
| duke@0 | // If 'fixed' is true, anon_mmap() will attempt to reserve anonymous memory
|
| duke@0 | // at 'requested_addr'. If there are existing memory mappings at the same
|
| duke@0 | // location, however, they will be overwritten. If 'fixed' is false,
|
| duke@0 | // 'requested_addr' is only treated as a hint, the return value may or
|
| duke@0 | // may not start from the requested address. Unlike Linux mmap(), this
|
| duke@0 | // function returns NULL to indicate failure.
|
| duke@0 | static char* anon_mmap(char* requested_addr, size_t bytes, bool fixed) {
|
| duke@0 | char * addr;
|
| duke@0 | int flags;
|
| duke@0 |
|
| duke@0 | flags = MAP_PRIVATE | MAP_NORESERVE | MAP_ANONYMOUS;
|
| duke@0 | if (fixed) {
|
| duke@0 | assert((uintptr_t)requested_addr % os::Linux::page_size() == 0, "unaligned address");
|
| duke@0 | flags |= MAP_FIXED;
|
| duke@0 | }
|
| duke@0 |
|
| coleenp@783 | // Map uncommitted pages PROT_READ and PROT_WRITE, change access
|
| coleenp@783 | // to PROT_EXEC if executable when we commit the page.
|
| coleenp@783 | addr = (char*)::mmap(requested_addr, bytes, PROT_READ|PROT_WRITE,
|
| duke@0 | flags, -1, 0);
|
| duke@0 |
|
| duke@0 | if (addr != MAP_FAILED) {
|
| duke@0 | // anon_mmap() should only get called during VM initialization,
|
| duke@0 | // don't need lock (actually we can skip locking even it can be called
|
| duke@0 | // from multiple threads, because _highest_vm_reserved_address is just a
|
| duke@0 | // hint about the upper limit of non-stack memory regions.)
|
| duke@0 | if ((address)addr + bytes > _highest_vm_reserved_address) {
|
| duke@0 | _highest_vm_reserved_address = (address)addr + bytes;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | return addr == MAP_FAILED ? NULL : addr;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Don't update _highest_vm_reserved_address, because there might be memory
|
| duke@0 | // regions above addr + size. If so, releasing a memory region only creates
|
| duke@0 | // a hole in the address space, it doesn't help prevent heap-stack collision.
|
| duke@0 | //
|
| duke@0 | static int anon_munmap(char * addr, size_t size) {
|
| duke@0 | return ::munmap(addr, size) == 0;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | char* os::reserve_memory(size_t bytes, char* requested_addr,
|
| duke@0 | size_t alignment_hint) {
|
| duke@0 | return anon_mmap(requested_addr, bytes, (requested_addr != NULL));
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | bool os::release_memory(char* addr, size_t size) {
|
| duke@0 | return anon_munmap(addr, size);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | static address highest_vm_reserved_address() {
|
| duke@0 | return _highest_vm_reserved_address;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | static bool linux_mprotect(char* addr, size_t size, int prot) {
|
| duke@0 | // Linux wants the mprotect address argument to be page aligned.
|
| duke@0 | char* bottom = (char*)align_size_down((intptr_t)addr, os::Linux::page_size());
|
| duke@0 |
|
| duke@0 | // According to SUSv3, mprotect() should only be used with mappings
|
| duke@0 | // established by mmap(), and mmap() always maps whole pages. Unaligned
|
| duke@0 | // 'addr' likely indicates problem in the VM (e.g. trying to change
|
| duke@0 | // protection of malloc'ed or statically allocated memory). Check the
|
| duke@0 | // caller if you hit this assert.
|
| duke@0 | assert(addr == bottom, "sanity check");
|
| duke@0 |
|
| duke@0 | size = align_size_up(pointer_delta(addr, bottom, 1) + size, os::Linux::page_size());
|
| duke@0 | return ::mprotect(bottom, size, prot) == 0;
|
| duke@0 | }
|
| duke@0 |
|
| coleenp@295 | // Set protections specified
|
| coleenp@295 | bool os::protect_memory(char* addr, size_t bytes, ProtType prot,
|
| coleenp@295 | bool is_committed) {
|
| coleenp@295 | unsigned int p = 0;
|
| coleenp@295 | switch (prot) {
|
| coleenp@295 | case MEM_PROT_NONE: p = PROT_NONE; break;
|
| coleenp@295 | case MEM_PROT_READ: p = PROT_READ; break;
|
| coleenp@295 | case MEM_PROT_RW: p = PROT_READ|PROT_WRITE; break;
|
| coleenp@295 | case MEM_PROT_RWX: p = PROT_READ|PROT_WRITE|PROT_EXEC; break;
|
| coleenp@295 | default:
|
| coleenp@295 | ShouldNotReachHere();
|
| coleenp@295 | }
|
| coleenp@295 | // is_committed is unused.
|
| coleenp@295 | return linux_mprotect(addr, bytes, p);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | bool os::guard_memory(char* addr, size_t size) {
|
| duke@0 | return linux_mprotect(addr, size, PROT_NONE);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | bool os::unguard_memory(char* addr, size_t size) {
|
| coleenp@533 | return linux_mprotect(addr, size, PROT_READ|PROT_WRITE);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Large page support
|
| duke@0 |
|
| duke@0 | static size_t _large_page_size = 0;
|
| duke@0 |
|
| duke@0 | bool os::large_page_init() {
|
| duke@0 | if (!UseLargePages) return false;
|
| duke@0 |
|
| duke@0 | if (LargePageSizeInBytes) {
|
| duke@0 | _large_page_size = LargePageSizeInBytes;
|
| duke@0 | } else {
|
| duke@0 | // large_page_size on Linux is used to round up heap size. x86 uses either
|
| duke@0 | // 2M or 4M page, depending on whether PAE (Physical Address Extensions)
|
| duke@0 | // mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use
|
| duke@0 | // page as large as 256M.
|
| duke@0 | //
|
| duke@0 | // Here we try to figure out page size by parsing /proc/meminfo and looking
|
| duke@0 | // for a line with the following format:
|
| duke@0 | // Hugepagesize: 2048 kB
|
| duke@0 | //
|
| duke@0 | // If we can't determine the value (e.g. /proc is not mounted, or the text
|
| duke@0 | // format has been changed), we'll use the largest page size supported by
|
| duke@0 | // the processor.
|
| duke@0 |
|
| never@1241 | #ifndef ZERO
|
| bobv@1892 | _large_page_size = IA32_ONLY(4 * M) AMD64_ONLY(2 * M) IA64_ONLY(256 * M) SPARC_ONLY(4 * M)
|
| bobv@1892 | ARM_ONLY(2 * M) PPC_ONLY(4 * M);
|
| never@1241 | #endif // ZERO
|
| duke@0 |
|
| duke@0 | FILE *fp = fopen("/proc/meminfo", "r");
|
| duke@0 | if (fp) {
|
| duke@0 | while (!feof(fp)) {
|
| duke@0 | int x = 0;
|
| duke@0 | char buf[16];
|
| duke@0 | if (fscanf(fp, "Hugepagesize: %d", &x) == 1) {
|
| duke@0 | if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) {
|
| duke@0 | _large_page_size = x * K;
|
| duke@0 | break;
|
| duke@0 | }
|
| duke@0 | } else {
|
| duke@0 | // skip to next line
|
| duke@0 | for (;;) {
|
| duke@0 | int ch = fgetc(fp);
|
| duke@0 | if (ch == EOF || ch == (int)'\n') break;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | fclose(fp);
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | const size_t default_page_size = (size_t)Linux::page_size();
|
| duke@0 | if (_large_page_size > default_page_size) {
|
| duke@0 | _page_sizes[0] = _large_page_size;
|
| duke@0 | _page_sizes[1] = default_page_size;
|
| duke@0 | _page_sizes[2] = 0;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Large page support is available on 2.6 or newer kernel, some vendors
|
| duke@0 | // (e.g. Redhat) have backported it to their 2.4 based distributions.
|
| duke@0 | // We optimistically assume the support is available. If later it turns out
|
| duke@0 | // not true, VM will automatically switch to use regular page size.
|
| duke@0 | return true;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | #ifndef SHM_HUGETLB
|
| duke@0 | #define SHM_HUGETLB 04000
|
| duke@0 | #endif
|
| duke@0 |
|
| coleenp@783 | char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) {
|
| coleenp@783 | // "exec" is passed in but not used. Creating the shared image for
|
| coleenp@783 | // the code cache doesn't have an SHM_X executable permission to check.
|
| duke@0 | assert(UseLargePages, "only for large pages");
|
| duke@0 |
|
| duke@0 | key_t key = IPC_PRIVATE;
|
| duke@0 | char *addr;
|
| duke@0 |
|
| duke@0 | bool warn_on_failure = UseLargePages &&
|
| duke@0 | (!FLAG_IS_DEFAULT(UseLargePages) ||
|
| duke@0 | !FLAG_IS_DEFAULT(LargePageSizeInBytes)
|
| duke@0 | );
|
| duke@0 | char msg[128];
|
| duke@0 |
|
| duke@0 | // Create a large shared memory region to attach to based on size.
|
| duke@0 | // Currently, size is the total size of the heap
|
| duke@0 | int shmid = shmget(key, bytes, SHM_HUGETLB|IPC_CREAT|SHM_R|SHM_W);
|
| duke@0 | if (shmid == -1) {
|
| duke@0 | // Possible reasons for shmget failure:
|
| duke@0 | // 1. shmmax is too small for Java heap.
|
| duke@0 | // > check shmmax value: cat /proc/sys/kernel/shmmax
|
| duke@0 | // > increase shmmax value: echo "0xffffffff" > /proc/sys/kernel/shmmax
|
| duke@0 | // 2. not enough large page memory.
|
| duke@0 | // > check available large pages: cat /proc/meminfo
|
| duke@0 | // > increase amount of large pages:
|
| duke@0 | // echo new_value > /proc/sys/vm/nr_hugepages
|
| duke@0 | // Note 1: different Linux may use different name for this property,
|
| duke@0 | // e.g. on Redhat AS-3 it is "hugetlb_pool".
|
| duke@0 | // Note 2: it's possible there's enough physical memory available but
|
| duke@0 | // they are so fragmented after a long run that they can't
|
| duke@0 | // coalesce into large pages. Try to reserve large pages when
|
| duke@0 | // the system is still "fresh".
|
| duke@0 | if (warn_on_failure) {
|
| duke@0 | jio_snprintf(msg, sizeof(msg), "Failed to reserve shared memory (errno = %d).", errno);
|
| duke@0 | warning(msg);
|
| duke@0 | }
|
| duke@0 | return NULL;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // attach to the region
|
| kvn@1747 | addr = (char*)shmat(shmid, req_addr, 0);
|
| duke@0 | int err = errno;
|
| duke@0 |
|
| duke@0 | // Remove shmid. If shmat() is successful, the actual shared memory segment
|
| duke@0 | // will be deleted when it's detached by shmdt() or when the process
|
| duke@0 | // terminates. If shmat() is not successful this will remove the shared
|
| duke@0 | // segment immediately.
|
| duke@0 | shmctl(shmid, IPC_RMID, NULL);
|
| duke@0 |
|
| duke@0 | if ((intptr_t)addr == -1) {
|
| duke@0 | if (warn_on_failure) {
|
| duke@0 | jio_snprintf(msg, sizeof(msg), "Failed to attach shared memory (errno = %d).", err);
|
| duke@0 | warning(msg);
|
| duke@0 | }
|
| duke@0 | return NULL;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | return addr;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | bool os::release_memory_special(char* base, size_t bytes) {
|
| duke@0 | // detaching the SHM segment will also delete it, see reserve_memory_special()
|
| duke@0 | int rslt = shmdt(base);
|
| duke@0 | return rslt == 0;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | size_t os::large_page_size() {
|
| duke@0 | return _large_page_size;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Linux does not support anonymous mmap with large page memory. The only way
|
| duke@0 | // to reserve large page memory without file backing is through SysV shared
|
| duke@0 | // memory API. The entire memory region is committed and pinned upfront.
|
| duke@0 | // Hopefully this will change in the future...
|
| duke@0 | bool os::can_commit_large_page_memory() {
|
| jcoomes@137 | return false;
|
| jcoomes@137 | }
|
| jcoomes@137 |
|
| jcoomes@137 | bool os::can_execute_large_page_memory() {
|
| duke@0 | return false;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Reserve memory at an arbitrary address, only if that area is
|
| duke@0 | // available (and not reserved for something else).
|
| duke@0 |
|
| duke@0 | char* os::attempt_reserve_memory_at(size_t bytes, char* requested_addr) {
|
| duke@0 | const int max_tries = 10;
|
| duke@0 | char* base[max_tries];
|
| duke@0 | size_t size[max_tries];
|
| duke@0 | const size_t gap = 0x000000;
|
| duke@0 |
|
| duke@0 | // Assert only that the size is a multiple of the page size, since
|
| duke@0 | // that's all that mmap requires, and since that's all we really know
|
| duke@0 | // about at this low abstraction level. If we need higher alignment,
|
| duke@0 | // we can either pass an alignment to this method or verify alignment
|
| duke@0 | // in one of the methods further up the call chain. See bug 5044738.
|
| duke@0 | assert(bytes % os::vm_page_size() == 0, "reserving unexpected size block");
|
| duke@0 |
|
| duke@0 | // Repeatedly allocate blocks until the block is allocated at the
|
| duke@0 | // right spot. Give up after max_tries. Note that reserve_memory() will
|
| duke@0 | // automatically update _highest_vm_reserved_address if the call is
|
| duke@0 | // successful. The variable tracks the highest memory address every reserved
|
| duke@0 | // by JVM. It is used to detect heap-stack collision if running with
|
| duke@0 | // fixed-stack LinuxThreads. Because here we may attempt to reserve more
|
| duke@0 | // space than needed, it could confuse the collision detecting code. To
|
| duke@0 | // solve the problem, save current _highest_vm_reserved_address and
|
| duke@0 | // calculate the correct value before return.
|
| duke@0 | address old_highest = _highest_vm_reserved_address;
|
| duke@0 |
|
| duke@0 | // Linux mmap allows caller to pass an address as hint; give it a try first,
|
| duke@0 | // if kernel honors the hint then we can return immediately.
|
| duke@0 | char * addr = anon_mmap(requested_addr, bytes, false);
|
| duke@0 | if (addr == requested_addr) {
|
| duke@0 | return requested_addr;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | if (addr != NULL) {
|
| duke@0 | // mmap() is successful but it fails to reserve at the requested address
|
| duke@0 | anon_munmap(addr, bytes);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | int i;
|
| duke@0 | for (i = 0; i < max_tries; ++i) {
|
| duke@0 | base[i] = reserve_memory(bytes);
|
| duke@0 |
|
| duke@0 | if (base[i] != NULL) {
|
| duke@0 | // Is this the block we wanted?
|
| duke@0 | if (base[i] == requested_addr) {
|
| duke@0 | size[i] = bytes;
|
| duke@0 | break;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Does this overlap the block we wanted? Give back the overlapped
|
| duke@0 | // parts and try again.
|
| duke@0 |
|
| duke@0 | size_t top_overlap = requested_addr + (bytes + gap) - base[i];
|
| duke@0 | if (top_overlap >= 0 && top_overlap < bytes) {
|
| duke@0 | unmap_memory(base[i], top_overlap);
|
| duke@0 | base[i] += top_overlap;
|
| duke@0 | size[i] = bytes - top_overlap;
|
| duke@0 | } else {
|
| duke@0 | size_t bottom_overlap = base[i] + bytes - requested_addr;
|
| duke@0 | if (bottom_overlap >= 0 && bottom_overlap < bytes) {
|
| duke@0 | unmap_memory(requested_addr, bottom_overlap);
|
| duke@0 | size[i] = bytes - bottom_overlap;
|
| duke@0 | } else {
|
| duke@0 | size[i] = bytes;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Give back the unused reserved pieces.
|
| duke@0 |
|
| duke@0 | for (int j = 0; j < i; ++j) {
|
| duke@0 | if (base[j] != NULL) {
|
| duke@0 | unmap_memory(base[j], size[j]);
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | if (i < max_tries) {
|
| duke@0 | _highest_vm_reserved_address = MAX2(old_highest, (address)requested_addr + bytes);
|
| duke@0 | return requested_addr;
|
| duke@0 | } else {
|
| duke@0 | _highest_vm_reserved_address = old_highest;
|
| duke@0 | return NULL;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | size_t os::read(int fd, void *buf, unsigned int nBytes) {
|
| duke@0 | return ::read(fd, buf, nBytes);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // TODO-FIXME: reconcile Solaris' os::sleep with the linux variation.
|
| duke@0 | // Solaris uses poll(), linux uses park().
|
| duke@0 | // Poll() is likely a better choice, assuming that Thread.interrupt()
|
| duke@0 | // generates a SIGUSRx signal. Note that SIGUSR1 can interfere with
|
| duke@0 | // SIGSEGV, see 4355769.
|
| duke@0 |
|
| duke@0 | const int NANOSECS_PER_MILLISECS = 1000000;
|
| duke@0 |
|
| duke@0 | int os::sleep(Thread* thread, jlong millis, bool interruptible) {
|
| duke@0 | assert(thread == Thread::current(), "thread consistency check");
|
| duke@0 |
|
| duke@0 | ParkEvent * const slp = thread->_SleepEvent ;
|
| duke@0 | slp->reset() ;
|
| duke@0 | OrderAccess::fence() ;
|
| duke@0 |
|
| duke@0 | if (interruptible) {
|
| duke@0 | jlong prevtime = javaTimeNanos();
|
| duke@0 |
|
| duke@0 | for (;;) {
|
| duke@0 | if (os::is_interrupted(thread, true)) {
|
| duke@0 | return OS_INTRPT;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | jlong newtime = javaTimeNanos();
|
| duke@0 |
|
| duke@0 | if (newtime - prevtime < 0) {
|
| duke@0 | // time moving backwards, should only happen if no monotonic clock
|
| duke@0 | // not a guarantee() because JVM should not abort on kernel/glibc bugs
|
| duke@0 | assert(!Linux::supports_monotonic_clock(), "time moving backwards");
|
| duke@0 | } else {
|
| duke@0 | millis -= (newtime - prevtime) / NANOSECS_PER_MILLISECS;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | if(millis <= 0) {
|
| duke@0 | return OS_OK;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | prevtime = newtime;
|
| duke@0 |
|
| duke@0 | {
|
| duke@0 | assert(thread->is_Java_thread(), "sanity check");
|
| duke@0 | JavaThread *jt = (JavaThread *) thread;
|
| duke@0 | ThreadBlockInVM tbivm(jt);
|
| duke@0 | OSThreadWaitState osts(jt->osthread(), false /* not Object.wait() */);
|
| duke@0 |
|
| duke@0 | jt->set_suspend_equivalent();
|
| duke@0 | // cleared by handle_special_suspend_equivalent_condition() or
|
| duke@0 | // java_suspend_self() via check_and_wait_while_suspended()
|
| duke@0 |
|
| duke@0 | slp->park(millis);
|
| duke@0 |
|
| duke@0 | // were we externally suspended while we were waiting?
|
| duke@0 | jt->check_and_wait_while_suspended();
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | } else {
|
| duke@0 | OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
|
| duke@0 | jlong prevtime = javaTimeNanos();
|
| duke@0 |
|
| duke@0 | for (;;) {
|
| duke@0 | // It'd be nice to avoid the back-to-back javaTimeNanos() calls on
|
| duke@0 | // the 1st iteration ...
|
| duke@0 | jlong newtime = javaTimeNanos();
|
| duke@0 |
|
| duke@0 | if (newtime - prevtime < 0) {
|
| duke@0 | // time moving backwards, should only happen if no monotonic clock
|
| duke@0 | // not a guarantee() because JVM should not abort on kernel/glibc bugs
|
| duke@0 | assert(!Linux::supports_monotonic_clock(), "time moving backwards");
|
| duke@0 | } else {
|
| duke@0 | millis -= (newtime - prevtime) / NANOSECS_PER_MILLISECS;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | if(millis <= 0) break ;
|
| duke@0 |
|
| duke@0 | prevtime = newtime;
|
| duke@0 | slp->park(millis);
|
| duke@0 | }
|
| duke@0 | return OS_OK ;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | int os::naked_sleep() {
|
| duke@0 | // %% make the sleep time an integer flag. for now use 1 millisec.
|
| duke@0 | return os::sleep(Thread::current(), 1, false);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Sleep forever; naked call to OS-specific sleep; use with CAUTION
|
| duke@0 | void os::infinite_sleep() {
|
| duke@0 | while (true) { // sleep forever ...
|
| duke@0 | ::sleep(100); // ... 100 seconds at a time
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Used to convert frequent JVM_Yield() to nops
|
| duke@0 | bool os::dont_yield() {
|
| duke@0 | return DontYieldALot;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | void os::yield() {
|
| duke@0 | sched_yield();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | os::YieldResult os::NakedYield() { sched_yield(); return os::YIELD_UNKNOWN ;}
|
| duke@0 |
|
| duke@0 | void os::yield_all(int attempts) {
|
| duke@0 | // Yields to all threads, including threads with lower priorities
|
| duke@0 | // Threads on Linux are all with same priority. The Solaris style
|
| duke@0 | // os::yield_all() with nanosleep(1ms) is not necessary.
|
| duke@0 | sched_yield();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Called from the tight loops to possibly influence time-sharing heuristics
|
| duke@0 | void os::loop_breaker(int attempts) {
|
| duke@0 | os::yield_all(attempts);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | ////////////////////////////////////////////////////////////////////////////////
|
| duke@0 | // thread priority support
|
| duke@0 |
|
| duke@0 | // Note: Normal Linux applications are run with SCHED_OTHER policy. SCHED_OTHER
|
| duke@0 | // only supports dynamic priority, static priority must be zero. For real-time
|
| duke@0 | // applications, Linux supports SCHED_RR which allows static priority (1-99).
|
| duke@0 | // However, for large multi-threaded applications, SCHED_RR is not only slower
|
| duke@0 | // than SCHED_OTHER, but also very unstable (my volano tests hang hard 4 out
|
| duke@0 | // of 5 runs - Sep 2005).
|
| duke@0 | //
|
| duke@0 | // The following code actually changes the niceness of kernel-thread/LWP. It
|
| duke@0 | // has an assumption that setpriority() only modifies one kernel-thread/LWP,
|
| duke@0 | // not the entire user process, and user level threads are 1:1 mapped to kernel
|
| duke@0 | // threads. It has always been the case, but could change in the future. For
|
| duke@0 | // this reason, the code should not be used as default (ThreadPriorityPolicy=0).
|
| duke@0 | // It is only used when ThreadPriorityPolicy=1 and requires root privilege.
|
| duke@0 |
|
| duke@0 | int os::java_to_os_priority[MaxPriority + 1] = {
|
| duke@0 | 19, // 0 Entry should never be used
|
| duke@0 |
|
| duke@0 | 4, // 1 MinPriority
|
| duke@0 | 3, // 2
|
| duke@0 | 2, // 3
|
| duke@0 |
|
| duke@0 | 1, // 4
|
| duke@0 | 0, // 5 NormPriority
|
| duke@0 | -1, // 6
|
| duke@0 |
|
| duke@0 | -2, // 7
|
| duke@0 | -3, // 8
|
| duke@0 | -4, // 9 NearMaxPriority
|
| duke@0 |
|
| duke@0 | -5 // 10 MaxPriority
|
| duke@0 | };
|
| duke@0 |
|
| duke@0 | static int prio_init() {
|
| duke@0 | if (ThreadPriorityPolicy == 1) {
|
| duke@0 | // Only root can raise thread priority. Don't allow ThreadPriorityPolicy=1
|
| duke@0 | // if effective uid is not root. Perhaps, a more elegant way of doing
|
| duke@0 | // this is to test CAP_SYS_NICE capability, but that will require libcap.so
|
| duke@0 | if (geteuid() != 0) {
|
| duke@0 | if (!FLAG_IS_DEFAULT(ThreadPriorityPolicy)) {
|
| duke@0 | warning("-XX:ThreadPriorityPolicy requires root privilege on Linux");
|
| duke@0 | }
|
| duke@0 | ThreadPriorityPolicy = 0;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | return 0;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | OSReturn os::set_native_priority(Thread* thread, int newpri) {
|
| duke@0 | if ( !UseThreadPriorities || ThreadPriorityPolicy == 0 ) return OS_OK;
|
| duke@0 |
|
| duke@0 | int ret = setpriority(PRIO_PROCESS, thread->osthread()->thread_id(), newpri);
|
| duke@0 | return (ret == 0) ? OS_OK : OS_ERR;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | OSReturn os::get_native_priority(const Thread* const thread, int *priority_ptr) {
|
| duke@0 | if ( !UseThreadPriorities || ThreadPriorityPolicy == 0 ) {
|
| duke@0 | *priority_ptr = java_to_os_priority[NormPriority];
|
| duke@0 | return OS_OK;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | errno = 0;
|
| duke@0 | *priority_ptr = getpriority(PRIO_PROCESS, thread->osthread()->thread_id());
|
| duke@0 | return (*priority_ptr != -1 || errno == 0 ? OS_OK : OS_ERR);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Hint to the underlying OS that a task switch would not be good.
|
| duke@0 | // Void return because it's a hint and can fail.
|
| duke@0 | void os::hint_no_preempt() {}
|
| duke@0 |
|
| duke@0 | ////////////////////////////////////////////////////////////////////////////////
|
| duke@0 | // suspend/resume support
|
| duke@0 |
|
| duke@0 | // the low-level signal-based suspend/resume support is a remnant from the
|
| duke@0 | // old VM-suspension that used to be for java-suspension, safepoints etc,
|
| duke@0 | // within hotspot. Now there is a single use-case for this:
|
| duke@0 | // - calling get_thread_pc() on the VMThread by the flat-profiler task
|
| duke@0 | // that runs in the watcher thread.
|
| duke@0 | // The remaining code is greatly simplified from the more general suspension
|
| duke@0 | // code that used to be used.
|
| duke@0 | //
|
| duke@0 | // The protocol is quite simple:
|
| duke@0 | // - suspend:
|
| duke@0 | // - sends a signal to the target thread
|
| duke@0 | // - polls the suspend state of the osthread using a yield loop
|
| duke@0 | // - target thread signal handler (SR_handler) sets suspend state
|
| duke@0 | // and blocks in sigsuspend until continued
|
| duke@0 | // - resume:
|
| duke@0 | // - sets target osthread state to continue
|
| duke@0 | // - sends signal to end the sigsuspend loop in the SR_handler
|
| duke@0 | //
|
| duke@0 | // Note that the SR_lock plays no role in this suspend/resume protocol.
|
| duke@0 | //
|
| duke@0 |
|
| duke@0 | static void resume_clear_context(OSThread *osthread) {
|
| duke@0 | osthread->set_ucontext(NULL);
|
| duke@0 | osthread->set_siginfo(NULL);
|
| duke@0 |
|
| duke@0 | // notify the suspend action is completed, we have now resumed
|
| duke@0 | osthread->sr.clear_suspended();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | static void suspend_save_context(OSThread *osthread, siginfo_t* siginfo, ucontext_t* context) {
|
| duke@0 | osthread->set_ucontext(context);
|
| duke@0 | osthread->set_siginfo(siginfo);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | //
|
| duke@0 | // Handler function invoked when a thread's execution is suspended or
|
| duke@0 | // resumed. We have to be careful that only async-safe functions are
|
| duke@0 | // called here (Note: most pthread functions are not async safe and
|
| duke@0 | // should be avoided.)
|
| duke@0 | //
|
| duke@0 | // Note: sigwait() is a more natural fit than sigsuspend() from an
|
| duke@0 | // interface point of view, but sigwait() prevents the signal hander
|
| duke@0 | // from being run. libpthread would get very confused by not having
|
| duke@0 | // its signal handlers run and prevents sigwait()'s use with the
|
| duke@0 | // mutex granting granting signal.
|
| duke@0 | //
|
| duke@0 | // Currently only ever called on the VMThread
|
| duke@0 | //
|
| duke@0 | static void SR_handler(int sig, siginfo_t* siginfo, ucontext_t* context) {
|
| duke@0 | // Save and restore errno to avoid confusing native code with EINTR
|
| duke@0 | // after sigsuspend.
|
| duke@0 | int old_errno = errno;
|
| duke@0 |
|
| duke@0 | Thread* thread = Thread::current();
|
| duke@0 | OSThread* osthread = thread->osthread();
|
| duke@0 | assert(thread->is_VM_thread(), "Must be VMThread");
|
| duke@0 | // read current suspend action
|
| duke@0 | int action = osthread->sr.suspend_action();
|
| duke@0 | if (action == SR_SUSPEND) {
|
| duke@0 | suspend_save_context(osthread, siginfo, context);
|
| duke@0 |
|
| duke@0 | // Notify the suspend action is about to be completed. do_suspend()
|
| duke@0 | // waits until SR_SUSPENDED is set and then returns. We will wait
|
| duke@0 | // here for a resume signal and that completes the suspend-other
|
| duke@0 | // action. do_suspend/do_resume is always called as a pair from
|
| duke@0 | // the same thread - so there are no races
|
| duke@0 |
|
| duke@0 | // notify the caller
|
| duke@0 | osthread->sr.set_suspended();
|
| duke@0 |
|
| duke@0 | sigset_t suspend_set; // signals for sigsuspend()
|
| duke@0 |
|
| duke@0 | // get current set of blocked signals and unblock resume signal
|
| duke@0 | pthread_sigmask(SIG_BLOCK, NULL, &suspend_set);
|
| duke@0 | sigdelset(&suspend_set, SR_signum);
|
| duke@0 |
|
| duke@0 | // wait here until we are resumed
|
| duke@0 | do {
|
| duke@0 | sigsuspend(&suspend_set);
|
| duke@0 | // ignore all returns until we get a resume signal
|
| duke@0 | } while (osthread->sr.suspend_action() != SR_CONTINUE);
|
| duke@0 |
|
| duke@0 | resume_clear_context(osthread);
|
| duke@0 |
|
| duke@0 | } else {
|
| duke@0 | assert(action == SR_CONTINUE, "unexpected sr action");
|
| duke@0 | // nothing special to do - just leave the handler
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | errno = old_errno;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 |
|
| duke@0 | static int SR_initialize() {
|
| duke@0 | struct sigaction act;
|
| duke@0 | char *s;
|
| duke@0 | /* Get signal number to use for suspend/resume */
|
| duke@0 | if ((s = ::getenv("_JAVA_SR_SIGNUM")) != 0) {
|
| duke@0 | int sig = ::strtol(s, 0, 10);
|
| duke@0 | if (sig > 0 || sig < _NSIG) {
|
| duke@0 | SR_signum = sig;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | assert(SR_signum > SIGSEGV && SR_signum > SIGBUS,
|
| duke@0 | "SR_signum must be greater than max(SIGSEGV, SIGBUS), see 4355769");
|
| duke@0 |
|
| duke@0 | sigemptyset(&SR_sigset);
|
| duke@0 | sigaddset(&SR_sigset, SR_signum);
|
| duke@0 |
|
| duke@0 | /* Set up signal handler for suspend/resume */
|
| duke@0 | act.sa_flags = SA_RESTART|SA_SIGINFO;
|
| duke@0 | act.sa_handler = (void (*)(int)) SR_handler;
|
| duke@0 |
|
| duke@0 | // SR_signum is blocked by default.
|
| duke@0 | // 4528190 - We also need to block pthread restart signal (32 on all
|
| duke@0 | // supported Linux platforms). Note that LinuxThreads need to block
|
| duke@0 | // this signal for all threads to work properly. So we don't have
|
| duke@0 | // to use hard-coded signal number when setting up the mask.
|
| duke@0 | pthread_sigmask(SIG_BLOCK, NULL, &act.sa_mask);
|
| duke@0 |
|
| duke@0 | if (sigaction(SR_signum, &act, 0) == -1) {
|
| duke@0 | return -1;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // Save signal flag
|
| duke@0 | os::Linux::set_our_sigflags(SR_signum, act.sa_flags);
|
| duke@0 | return 0;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | static int SR_finalize() {
|
| duke@0 | return 0;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 |
|
| duke@0 | // returns true on success and false on error - really an error is fatal
|
| duke@0 | // but this seems the normal response to library errors
|
| duke@0 | static bool do_suspend(OSThread* osthread) {
|
| duke@0 | // mark as suspended and send signal
|
| duke@0 | osthread->sr.set_suspend_action(SR_SUSPEND);
|
| duke@0 | int status = pthread_kill(osthread->pthread_id(), SR_signum);
|
| duke@0 | assert_status(status == 0, status, "pthread_kill");
|
| duke@0 |
|
| duke@0 | // check status and wait until notified of suspension
|
| duke@0 | if (status == 0) {
|
| duke@0 | for (int i = 0; !osthread->sr.is_suspended(); i++) {
|
| duke@0 | os::yield_all(i);
|
| duke@0 | }
|
| duke@0 | osthread->sr.set_suspend_action(SR_NONE);
|
| duke@0 | return true;
|
| duke@0 | }
|
| duke@0 | else {
|
| duke@0 | osthread->sr.set_suspend_action(SR_NONE);
|
| duke@0 | return false;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | static void do_resume(OSThread* osthread) {
|
| duke@0 | assert(osthread->sr.is_suspended(), "thread should be suspended");
|
| duke@0 | osthread->sr.set_suspend_action(SR_CONTINUE);
|
| duke@0 |
|
| duke@0 | int status = pthread_kill(osthread->pthread_id(), SR_signum);
|
| duke@0 | assert_status(status == 0, status, "pthread_kill");
|
| duke@0 | // check status and wait unit notified of resumption
|
| duke@0 | if (status == 0) {
|
| duke@0 | for (int i = 0; osthread->sr.is_suspended(); i++) {
|
| duke@0 | os::yield_all(i);
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | osthread->sr.set_suspend_action(SR_NONE);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | ////////////////////////////////////////////////////////////////////////////////
|
| duke@0 | // interrupt support
|
| duke@0 |
|
| duke@0 | void os::interrupt(Thread* thread) {
|
| duke@0 | assert(Thread::current() == thread || Threads_lock->owned_by_self(),
|
| duke@0 | "possibility of dangling Thread pointer");
|
| duke@0 |
|
| duke@0 | OSThread* osthread = thread->osthread();
|
| duke@0 |
|
| duke@0 | if (!osthread->interrupted()) {
|
| duke@0 | osthread->set_interrupted(true);
|
| duke@0 | // More than one thread can get here with the same value of osthread,
|
| duke@0 | // resulting in multiple notifications. We do, however, want the store
|
| duke@0 | // to interrupted() to be visible to other threads before we execute unpark().
|
| duke@0 | OrderAccess::fence();
|
| duke@0 | ParkEvent * const slp = thread->_SleepEvent ;
|
| duke@0 | if (slp != NULL) slp->unpark() ;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // For JSR166. Unpark even if interrupt status already was set
|
| duke@0 | if (thread->is_Java_thread())
|
| duke@0 | ((JavaThread*)thread)->parker()->unpark();
|
| duke@0 |
|
| duke@0 | ParkEvent * ev = thread->_ParkEvent ;
|
| duke@0 | if (ev != NULL) ev->unpark() ;
|
| duke@0 |
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
|
| duke@0 | assert(Thread::current() == thread || Threads_lock->owned_by_self(),
|
| duke@0 | "possibility of dangling Thread pointer");
|
| duke@0 |
|
| duke@0 | OSThread* osthread = thread->osthread();
|
| duke@0 |
|
| duke@0 | bool interrupted = osthread->interrupted();
|
| duke@0 |
|
| duke@0 | if (interrupted && clear_interrupted) {
|
| duke@0 | osthread->set_interrupted(false);
|
| duke@0 | // consider thread->_SleepEvent->reset() ... optional optimization
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | return interrupted;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | ///////////////////////////////////////////////////////////////////////////////////
|
| duke@0 | // signal handling (except suspend/resume)
|
| duke@0 |
|
| duke@0 | // This routine may be used by user applications as a "hook" to catch signals.
|
| duke@0 | // The user-defined signal handler must pass unrecognized signals to this
|
| duke@0 | // routine, and if it returns true (non-zero), then the signal handler must
|
| duke@0 | // return immediately. If the flag "abort_if_unrecognized" is true, then this
|
| duke@0 | // routine will never retun false (zero), but instead will execute a VM panic
|
| duke@0 | // routine kill the process.
|
| duke@0 | //
|
| duke@0 | // If this routine returns false, it is OK to call it again. This allows
|
| duke@0 | // the user-defined signal handler to perform checks either before or after
|
| duke@0 | // the VM performs its own checks. Naturally, the user code would be making
|
| duke@0 | // a serious error if it tried to handle an exception (such as a null check
|
| duke@0 | // or breakpoint) that the VM was generating for its own correct operation.
|
| duke@0 | //
|
| duke@0 | // This routine may recognize any of the following kinds of signals:
|
| duke@0 | // SIGBUS, SIGSEGV, SIGILL, SIGFPE, SIGQUIT, SIGPIPE, SIGXFSZ, SIGUSR1.
|
| duke@0 | // It should be consulted by handlers for any of those signals.
|
| duke@0 | //
|
| duke@0 | // The caller of this routine must pass in the three arguments supplied
|
| duke@0 | // to the function referred to in the "sa_sigaction" (not the "sa_handler")
|
| duke@0 | // field of the structure passed to sigaction(). This routine assumes that
|
| duke@0 | // the sa_flags field passed to sigaction() includes SA_SIGINFO and SA_RESTART.
|
| duke@0 | //
|
| duke@0 | // Note that the VM will print warnings if it detects conflicting signal
|
| duke@0 | // handlers, unless invoked with the option "-XX:+AllowUserSignalHandlers".
|
| duke@0 | //
|
| duke@0 | extern "C" int
|
| duke@0 | JVM_handle_linux_signal(int signo, siginfo_t* siginfo,
|
| duke@0 | void* ucontext, int abort_if_unrecognized);
|
| duke@0 |
|
| duke@0 | void signalHandler(int sig, siginfo_t* info, void* uc) {
|
| duke@0 | assert(info != NULL && uc != NULL, "it must be old kernel");
|
| duke@0 | JVM_handle_linux_signal(sig, info, uc, true);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 |
|
| duke@0 | // This boolean allows users to forward their own non-matching signals
|
| duke@0 | // to JVM_handle_linux_signal, harmlessly.
|
| duke@0 | bool os::Linux::signal_handlers_are_installed = false;
|
| duke@0 |
|
| duke@0 | // For signal-chaining
|
| duke@0 | struct sigaction os::Linux::sigact[MAXSIGNUM];
|
| duke@0 | unsigned int os::Linux::sigs = 0;
|
| duke@0 | bool os::Linux::libjsig_is_loaded = false;
|
| duke@0 | typedef struct sigaction *(*get_signal_t)(int);
|
| duke@0 | get_signal_t os::Linux::get_signal_action = NULL;
|
| duke@0 |
|
| duke@0 | struct sigaction* os::Linux::get_chained_signal_action(int sig) {
|
| duke@0 | struct sigaction *actp = NULL;
|
| duke@0 |
|
| duke@0 | if (libjsig_is_loaded) {
|
| duke@0 | // Retrieve the old signal handler from libjsig
|
| duke@0 | actp = (*get_signal_action)(sig);
|
| duke@0 | }
|
| duke@0 | if (actp == NULL) {
|
| duke@0 | // Retrieve the preinstalled signal handler from jvm
|
| duke@0 | actp = get_preinstalled_handler(sig);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | return actp;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | static bool call_chained_handler(struct sigaction *actp, int sig,
|
| duke@0 | siginfo_t *siginfo, void *context) {
|
| duke@0 | // Call the old signal handler
|
| duke@0 | if (actp->sa_handler == SIG_DFL) {
|
| duke@0 | // It's more reasonable to let jvm treat it as an unexpected exception
|
| duke@0 | // instead of taking the default action.
|
| duke@0 | return false;
|
| duke@0 | } else if (actp->sa_handler != SIG_IGN) {
|
| duke@0 | if ((actp->sa_flags & SA_NODEFER) == 0) {
|
| duke@0 | // automaticlly block the signal
|
| duke@0 | sigaddset(&(actp->sa_mask), sig);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | sa_handler_t hand;
|
| duke@0 | sa_sigaction_t sa;
|
| duke@0 | bool siginfo_flag_set = (actp->sa_flags & SA_SIGINFO) != 0;
|
| duke@0 | // retrieve the chained handler
|
| duke@0 | if (siginfo_flag_set) {
|
| duke@0 | sa = actp->sa_sigaction;
|
| duke@0 | } else {
|
| duke@0 | hand = actp->sa_handler;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | if ((actp->sa_flags & SA_RESETHAND) != 0) {
|
| duke@0 | actp->sa_handler = SIG_DFL;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // try to honor the signal mask
|
| duke@0 | sigset_t oset;
|
| duke@0 | pthread_sigmask(SIG_SETMASK, &(actp->sa_mask), &oset);
|
| duke@0 |
|
| duke@0 | // call into the chained handler
|
| duke@0 | if (siginfo_flag_set) {
|
| duke@0 | (*sa)(sig, siginfo, context);
|
| duke@0 | } else {
|
| duke@0 | (*hand)(sig);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // restore the signal mask
|
| duke@0 | pthread_sigmask(SIG_SETMASK, &oset, 0);
|
| duke@0 | }
|
| duke@0 | // Tell jvm's signal handler the signal is taken care of.
|
| duke@0 | return true;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | bool os::Linux::chained_handler(int sig, siginfo_t* siginfo, void* context) {
|
| duke@0 | bool chained = false;
|
| duke@0 | // signal-chaining
|
| duke@0 | if (UseSignalChaining) {
|
| duke@0 | struct sigaction *actp = get_chained_signal_action(sig);
|
| duke@0 | if (actp != NULL) {
|
| duke@0 | chained = call_chained_handler(actp, sig, siginfo, context);
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | return chained;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | struct sigaction* os::Linux::get_preinstalled_handler(int sig) {
|
| duke@0 | if ((( (unsigned int)1 << sig ) & sigs) != 0) {
|
| duke@0 | return &sigact[sig];
|
| duke@0 | }
|
| duke@0 | return NULL;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | void os::Linux::save_preinstalled_handler(int sig, struct sigaction& oldAct) {
|
| duke@0 | assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range");
|
| duke@0 | sigact[sig] = oldAct;
|
| duke@0 | sigs |= (unsigned int)1 << sig;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // for diagnostic
|
| duke@0 | int os::Linux::sigflags[MAXSIGNUM];
|
| duke@0 |
|
| duke@0 | int os::Linux::get_our_sigflags(int sig) {
|
| duke@0 | assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range");
|
| duke@0 | return sigflags[sig];
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | void os::Linux::set_our_sigflags(int sig, int flags) {
|
| duke@0 | assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range");
|
| duke@0 | sigflags[sig] = flags;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | void os::Linux::set_signal_handler(int sig, bool set_installed) {
|
| duke@0 | // Check for overwrite.
|
| duke@0 | struct sigaction oldAct;
|
| duke@0 | sigaction(sig, (struct sigaction*)NULL, &oldAct);
|
| duke@0 |
|
| duke@0 | void* oldhand = oldAct.sa_sigaction
|
| duke@0 | ? CAST_FROM_FN_PTR(void*, oldAct.sa_sigaction)
|
| duke@0 | : CAST_FROM_FN_PTR(void*, oldAct.sa_handler);
|
| duke@0 | if (oldhand != CAST_FROM_FN_PTR(void*, SIG_DFL) &&
|
| duke@0 | oldhand != CAST_FROM_FN_PTR(void*, SIG_IGN) &&
|
| duke@0 | oldhand != CAST_FROM_FN_PTR(void*, (sa_sigaction_t)signalHandler)) {
|
| duke@0 | if (AllowUserSignalHandlers || !set_installed) {
|
| duke@0 | // Do not overwrite; user takes responsibility to forward to us.
|
| duke@0 | return;
|
| duke@0 | } else if (UseSignalChaining) {
|
| duke@0 | // save the old handler in jvm
|
| duke@0 | save_preinstalled_handler(sig, oldAct);
|
| duke@0 | // libjsig also interposes the sigaction() call below and saves the
|
| duke@0 | // old sigaction on it own.
|
| duke@0 | } else {
|
| jcoomes@1700 | fatal(err_msg("Encountered unexpected pre-existing sigaction handler "
|
| jcoomes@1700 | "%#lx for signal %d.", (long)oldhand, sig));
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | struct sigaction sigAct;
|
| duke@0 | sigfillset(&(sigAct.sa_mask));
|
| duke@0 | sigAct.sa_handler = SIG_DFL;
|
| duke@0 | if (!set_installed) {
|
| duke@0 | sigAct.sa_flags = SA_SIGINFO|SA_RESTART;
|
| duke@0 | } else {
|
| duke@0 | sigAct.sa_sigaction = signalHandler;
|
| duke@0 | sigAct.sa_flags = SA_SIGINFO|SA_RESTART;
|
| duke@0 | }
|
| duke@0 | // Save flags, which are set by ours
|
| duke@0 | assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range");
|
| duke@0 | sigflags[sig] = sigAct.sa_flags;
|
| duke@0 |
|
| duke@0 | int ret = sigaction(sig, &sigAct, &oldAct);
|
| duke@0 | assert(ret == 0, "check");
|
| duke@0 |
|
| duke@0 | void* oldhand2 = oldAct.sa_sigaction
|
| duke@0 | ? CAST_FROM_FN_PTR(void*, oldAct.sa_sigaction)
|
| duke@0 | : CAST_FROM_FN_PTR(void*, oldAct.sa_handler);
|
| duke@0 | assert(oldhand2 == oldhand, "no concurrent signal handler installation");
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // install signal handlers for signals that HotSpot needs to
|
| duke@0 | // handle in order to support Java-level exception handling.
|
| duke@0 |
|
| duke@0 | void os::Linux::install_signal_handlers() {
|
| duke@0 | if (!signal_handlers_are_installed) {
|
| duke@0 | signal_handlers_are_installed = true;
|
| duke@0 |
|
| duke@0 | // signal-chaining
|
| duke@0 | typedef void (*signal_setting_t)();
|
| duke@0 | signal_setting_t begin_signal_setting = NULL;
|
| duke@0 | signal_setting_t end_signal_setting = NULL;
|
| duke@0 | begin_signal_setting = CAST_TO_FN_PTR(signal_setting_t,
|
| duke@0 | dlsym(RTLD_DEFAULT, "JVM_begin_signal_setting"));
|
| duke@0 | if (begin_signal_setting != NULL) {
|
| duke@0 | end_signal_setting = CAST_TO_FN_PTR(signal_setting_t,
|
| duke@0 | dlsym(RTLD_DEFAULT, "JVM_end_signal_setting"));
|
| duke@0 | get_signal_action = CAST_TO_FN_PTR(get_signal_t,
|
| duke@0 | dlsym(RTLD_DEFAULT, "JVM_get_signal_action"));
|
| duke@0 | libjsig_is_loaded = true;
|
| duke@0 | assert(UseSignalChaining, "should enable signal-chaining");
|
| duke@0 | }
|
| duke@0 | if (libjsig_is_loaded) {
|
| duke@0 | // Tell libjsig jvm is setting signal handlers
|
| duke@0 | (*begin_signal_setting)();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | set_signal_handler(SIGSEGV, true);
|
| duke@0 | set_signal_handler(SIGPIPE, true);
|
| duke@0 | set_signal_handler(SIGBUS, true);
|
| duke@0 | set_signal_handler(SIGILL, true);
|
| duke@0 | set_signal_handler(SIGFPE, true);
|
| duke@0 | set_signal_handler(SIGXFSZ, true);
|
| duke@0 |
|
| duke@0 | if (libjsig_is_loaded) {
|
| duke@0 | // Tell libjsig jvm finishes setting signal handlers
|
| duke@0 | (*end_signal_setting)();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // We don't activate signal checker if libjsig is in place, we trust ourselves
|
| duke@0 | // and if UserSignalHandler is installed all bets are off
|
| duke@0 | if (CheckJNICalls) {
|
| duke@0 | if (libjsig_is_loaded) {
|
| duke@0 | tty->print_cr("Info: libjsig is activated, all active signal checking is disabled");
|
| duke@0 | check_signals = false;
|
| duke@0 | }
|
| duke@0 | if (AllowUserSignalHandlers) {
|
| duke@0 | tty->print_cr("Info: AllowUserSignalHandlers is activated, all active signal checking is disabled");
|
| duke@0 | check_signals = false;
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | // This is the fastest way to get thread cpu time on Linux.
|
| duke@0 | // Returns cpu time (user+sys) for any thread, not only for current.
|
| duke@0 | // POSIX compliant clocks are implemented in the kernels 2.6.16+.
|
| duke@0 | // It might work on 2.6.10+ with a special kernel/glibc patch.
|
| duke@0 | // For reference, please, see IEEE Std 1003.1-2004:
|
| duke@0 | // http://www.unix.org/single_unix_specification
|
| duke@0 |
|
| duke@0 | jlong os::Linux::fast_thread_cpu_time(clockid_t clockid) {
|
| duke@0 | struct timespec tp;
|
| duke@0 | int rc = os::Linux::clock_gettime(clockid, &tp);
|
| duke@0 | assert(rc == 0, "clock_gettime is expected to return 0 code");
|
| duke@0 |
|
| duke@0 | return (tp.tv_sec * SEC_IN_NANOSECS) + tp.tv_nsec;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | /////
|
| duke@0 | // glibc on Linux platform uses non-documented flag
|
| duke@0 | // to indicate, that some special sort of signal
|
| duke@0 | // trampoline is used.
|
| duke@0 | // We will never set this flag, and we should
|
| duke@0 | // ignore this flag in our diagnostic
|
| duke@0 | #ifdef SIGNIFICANT_SIGNAL_MASK
|
| duke@0 | #undef SIGNIFICANT_SIGNAL_MASK
|
| duke@0 | #endif
|
| duke@0 | #define SIGNIFICANT_SIGNAL_MASK (~0x04000000)
|
| duke@0 |
|
| duke@0 | static const char* get_signal_handler_name(address handler,
|
| duke@0 | char* buf, int buflen) {
|
| duke@0 | int offset;
|
| duke@0 | bool found = os::dll_address_to_library_name(handler, buf, buflen, &offset);
|
| duke@0 | if (found) {
|
| duke@0 | // skip directory names
|
| duke@0 | const char *p1, *p2;
|
| duke@0 | p1 = buf;
|
| duke@0 | size_t len = strlen(os::file_separator());
|
| duke@0 | while ((p2 = strstr(p1, os::file_separator())) != NULL) p1 = p2 + len;
|
| duke@0 | jio_snprintf(buf, buflen, "%s+0x%x", p1, offset);
|
| duke@0 | } else {
|
| duke@0 | jio_snprintf(buf, buflen, PTR_FORMAT, handler);
|
| duke@0 | }
|
| duke@0 | return buf;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | static void print_signal_handler(outputStream* st, int sig,
|
| duke@0 | char* buf, size_t buflen) {
|
| duke@0 | struct sigaction sa;
|
| duke@0 |
|
| duke@0 | sigaction(sig, NULL, &sa);
|
| duke@0 |
|
| duke@0 | // See comment for SIGNIFICANT_SIGNAL_MASK define
|
| duke@0 | sa.sa_flags &= SIGNIFICANT_SIGNAL_MASK;
|
| duke@0 |
|
| duke@0 | st->print("%s: ", os::exception_name(sig, buf, buflen));
|
| duke@0 |
|
| duke@0 | address handler = (sa.sa_flags & SA_SIGINFO)
|
| duke@0 | ? CAST_FROM_FN_PTR(address, sa.sa_sigaction)
|
| duke@0 | : CAST_FROM_FN_PTR(address, sa.sa_handler);
|
| duke@0 |
|
| duke@0 | if (handler == CAST_FROM_FN_PTR(address, SIG_DFL)) {
|
| duke@0 | st->print("SIG_DFL");
|
| duke@0 | } else if (handler == CAST_FROM_FN_PTR(address, SIG_IGN)) {
|
| duke@0 | st->print("SIG_IGN");
|
| duke@0 | } else {
|
| duke@0 | st->print("[%s]", get_signal_handler_name(handler, buf, buflen));
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | st->print(", sa_mask[0]=" PTR32_FORMAT, *(uint32_t*)&sa.sa_mask);
|
| duke@0 |
|
| duke@0 | address rh = VMError::get_resetted_sighandler(sig);
|
| duke@0 | // May be, handler was resetted by VMError?
|
| duke@0 | if(rh != NULL) {
|
| duke@0 | handler = rh;
|
| duke@0 | sa.sa_flags = VMError::get_resetted_sigflags(sig) & SIGNIFICANT_SIGNAL_MASK;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | st->print(", sa_flags=" PTR32_FORMAT, sa.sa_flags);
|
| duke@0 |
|
| duke@0 | // Check: is it our handler?
|
| duke@0 | if(handler == CAST_FROM_FN_PTR(address, (sa_sigaction_t)signalHandler) ||
|
| duke@0 | handler == CAST_FROM_FN_PTR(address, (sa_sigaction_t)SR_handler)) {
|
| duke@0 | // It is our signal handler
|
| duke@0 | // check for flags, reset system-used one!
|
| duke@0 | if((int)sa.sa_flags != os::Linux::get_our_sigflags(sig)) {
|
| duke@0 | st->print(
|
| duke@0 | ", flags was changed from " PTR32_FORMAT ", consider using jsig library",
|
| duke@0 | os::Linux::get_our_sigflags(sig));
|
| duke@0 | }
|
| duke@0 | }
|
| duke@0 | st->cr();
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 |
|
| duke@0 | #define DO_SIGNAL_CHECK(sig) \
|
| duke@0 | if (!sigismember(&check_signal_done, sig)) \
|
| duke@0 | os::Linux::check_signal_handler(sig)
|
| duke@0 |
|
| duke@0 | // This method is a periodic task to check for misbehaving JNI applications
|
| duke@0 | // under CheckJNI, we can add any periodic checks here
|
| duke@0 |
|
| duke@0 | void os::run_periodic_checks() {
|
| duke@0 |
|
| duke@0 | if (check_signals == false) return;
|
| duke@0 |
|
| duke@0 | // SEGV and BUS if overridden could potentially prevent
|
| duke@0 | // generation of hs*.log in the event of a crash, debugging
|
| duke@0 | // such a case can be very challenging, so we absolutely
|
| duke@0 | // check the following for a good measure:
|
| duke@0 | DO_SIGNAL_CHECK(SIGSEGV);
|
| duke@0 | DO_SIGNAL_CHECK(SIGILL);
|
| duke@0 | DO_SIGNAL_CHECK(SIGFPE);
|
| duke@0 | DO_SIGNAL_CHECK(SIGBUS);
|
| duke@0 | DO_SIGNAL_CHECK(SIGPIPE);
|
| duke@0 | DO_SIGNAL_CHECK(SIGXFSZ);
|
| duke@0 |
|
| duke@0 |
|
| duke@0 | // ReduceSignalUsage allows the user to override these handlers
|
| duke@0 | // see comments at the very top and jvm_solaris.h
|
| duke@0 | if (!ReduceSignalUsage) {
|
| duke@0 | DO_SIGNAL_CHECK(SHUTDOWN1_SIGNAL);
|
| duke@0 | DO_SIGNAL_CHECK(SHUTDOWN2_SIGNAL);
|
| duke@0 | DO_SIGNAL_CHECK(SHUTDOWN3_SIGNAL);
|
| duke@0 | DO_SIGNAL_CHECK(BREAK_SIGNAL);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | DO_SIGNAL_CHECK(SR_signum);
|
| duke@0 | DO_SIGNAL_CHECK(INTERRUPT_SIGNAL);
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | typedef int (*os_sigaction_t)(int, const struct sigaction *, struct sigaction *);
|
| duke@0 |
|
| duke@0 | static os_sigaction_t os_sigaction = NULL;
|
| duke@0 |
|
| duke@0 | void os::Linux::check_signal_handler(int sig) {
|
| duke@0 | char buf[O_BUFLEN];
|
| duke@0 | address jvmHandler = NULL;
|
| duke@0 |
|
| duke@0 |
|
| duke@0 | struct sigaction act;
|
| duke@0 | if (os_sigaction == NULL) {
|
| duke@0 | // only trust the default sigaction, in case it has been interposed
|
| duke@0 | os_sigaction = (os_sigaction_t)dlsym(RTLD_DEFAULT, "sigaction");
|
| duke@0 | if (os_sigaction == NULL) return;
|
| duke@0 | }
|
| duke@0 |
|
| duke@0 | os_sigaction(sig, (struct sigaction*)NULL, &act);
|
| duke@0 |
|
| duke@0 |
|
| duke@0 | act.sa_flags &= SIGNIFICANT_SIGNAL_MASK;
|
| duke@0 |
|
| duke@0 | address thisHandler = (act.sa_flags & SA_SIGINFO)
|
| duke@0 | ? CAST_FROM_FN_PTR(address, act.sa_sigaction)
|
| duke@0 | : CAST_FROM_FN_PTR(address, act.sa_handler) ;
|
| duke@0 |
|
| duke@0 |
|
| duke@0 | switch(sig) {
|
| duke@0 | case SIGSEGV:
|
| duke@0 | case SIGBUS:
|
| duke@0 | case SIGFPE:
|
| duke@0 | case SIGPIPE:
|
| duke@0 | case SIGILL:
|
| duke@0 | case SIGXFSZ:
|
| duke@0 | jvmHandler = CAST_FROM_FN_PTR(address, (sa_sigaction_t)signalHandler);
|
| duke@0 | break;
|
| duke@0 |
|
| duke@0 | case SHUTDOWN1_SIGNAL:
|
| duke@0 | case SHUTDOWN2_SIGNAL:
|
| duke@0 | case SHUTDOWN3_SIGNAL:
|
| duke@0 | case BREAK_SIGNAL:
|
| duke@0 | jvmHandler = (address)user_handler();
|
| duke@0 | break;
|
| duke@0 |
|
| duke@0 | case INTERRUPT_SIGNAL:
|
| duke@0 | jvmHandler = CAST_FROM_FN_PTR(address, SIG_DFL);
|
| duke@0 | break;
|
| duke@0 |
|
| duke@0 | default:
|
| duke@0 | if (sig == SR_signum) {
|
| duke@0 | jvmHandler = CAST_FROM_FN_PTR(address, (sa_sigaction_t)SR_handler);
|
| duke@0 | } else {
|
| duke@0 | return;
|
|