src/os/solaris/vm/os_solaris.cpp
author coleenp
Wed Jan 12 13:59:18 2011 -0800 (2 years ago)
changeset 1999 2c8e1acf0433
parent 1958b69c41ea1764
child 2412a541ca8fa0e3
permissions -rw-r--r--
7009828: Fix for 6938627 breaks visualvm monitoring when -Djava.io.tmpdir is defined
Summary: Change get_temp_directory() back to /tmp and %TEMP% like it always was and where the tools expect it to be.
Reviewed-by: phh, dcubed, kamg, alanb
duke@0
/*
trims@1772
 * Copyright (c) 1997, 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
 */
duke@0
duke@0
// do not include  precompiled  header file
duke@0
# include "incls/_os_solaris.cpp.incl"
duke@0
duke@0
// put OS-includes here
duke@0
# include <dlfcn.h>
duke@0
# include <errno.h>
duke@0
# include <link.h>
duke@0
# include <poll.h>
duke@0
# include <pthread.h>
duke@0
# include <pwd.h>
duke@0
# include <schedctl.h>
duke@0
# include <setjmp.h>
duke@0
# include <signal.h>
duke@0
# include <stdio.h>
duke@0
# include <alloca.h>
duke@0
# include <sys/filio.h>
duke@0
# include <sys/ipc.h>
duke@0
# include <sys/lwp.h>
duke@0
# include <sys/machelf.h>     // for elf Sym structure used by dladdr1
duke@0
# include <sys/mman.h>
duke@0
# include <sys/processor.h>
duke@0
# include <sys/procset.h>
duke@0
# include <sys/pset.h>
duke@0
# include <sys/resource.h>
duke@0
# include <sys/shm.h>
duke@0
# include <sys/socket.h>
duke@0
# include <sys/stat.h>
duke@0
# include <sys/systeminfo.h>
duke@0
# include <sys/time.h>
duke@0
# include <sys/times.h>
duke@0
# include <sys/types.h>
duke@0
# include <sys/wait.h>
duke@0
# include <sys/utsname.h>
duke@0
# include <thread.h>
duke@0
# include <unistd.h>
duke@0
# include <sys/priocntl.h>
duke@0
# include <sys/rtpriocntl.h>
duke@0
# include <sys/tspriocntl.h>
duke@0
# include <sys/iapriocntl.h>
duke@0
# include <sys/loadavg.h>
duke@0
# include <string.h>
duke@0
duke@0
# define _STRUCTURED_PROC 1  //  this gets us the new structured proc interfaces of 5.6 & later
duke@0
# include <sys/procfs.h>     //  see comment in <sys/procfs.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
duke@0
#ifdef _GNU_SOURCE
duke@0
// See bug #6514594
duke@0
extern "C" int madvise(caddr_t, size_t, int);
duke@0
extern "C"  int memcntl(caddr_t addr, size_t len, int cmd, caddr_t  arg,
duke@0
     int attr, int mask);
duke@0
#endif //_GNU_SOURCE
duke@0
duke@0
/*
duke@0
  MPSS Changes Start.
duke@0
  The JVM binary needs to be built and run on pre-Solaris 9
duke@0
  systems, but the constants needed by MPSS are only in Solaris 9
duke@0
  header files.  They are textually replicated here to allow
duke@0
  building on earlier systems.  Once building on Solaris 8 is
duke@0
  no longer a requirement, these #defines can be replaced by ordinary
duke@0
  system .h inclusion.
duke@0
duke@0
  In earlier versions of the  JDK and Solaris, we used ISM for large pages.
duke@0
  But ISM requires shared memory to achieve this and thus has many caveats.
duke@0
  MPSS is a fully transparent and is a cleaner way to get large pages.
duke@0
  Although we still require keeping ISM for backward compatiblitiy as well as
duke@0
  giving the opportunity to use large pages on older systems it is
duke@0
  recommended that MPSS be used for Solaris 9 and above.
duke@0
duke@0
*/
duke@0
duke@0
#ifndef MC_HAT_ADVISE
duke@0
duke@0
struct memcntl_mha {
duke@0
  uint_t          mha_cmd;        /* command(s) */
duke@0
  uint_t          mha_flags;
duke@0
  size_t          mha_pagesize;
duke@0
};
duke@0
#define MC_HAT_ADVISE   7       /* advise hat map size */
duke@0
#define MHA_MAPSIZE_VA  0x1     /* set preferred page size */
duke@0
#define MAP_ALIGN       0x200   /* addr specifies alignment */
duke@0
duke@0
#endif
duke@0
// MPSS Changes End.
duke@0
duke@0
duke@0
// Here are some liblgrp types from sys/lgrp_user.h to be able to
duke@0
// compile on older systems without this header file.
duke@0
duke@0
#ifndef MADV_ACCESS_LWP
duke@0
# define  MADV_ACCESS_LWP         7       /* next LWP to access heavily */
duke@0
#endif
duke@0
#ifndef MADV_ACCESS_MANY
duke@0
# define  MADV_ACCESS_MANY        8       /* many processes to access heavily */
duke@0
#endif
duke@0
iveresov@201
#ifndef LGRP_RSRC_CPU
iveresov@201
# define LGRP_RSRC_CPU           0       /* CPU resources */
iveresov@201
#endif
iveresov@201
#ifndef LGRP_RSRC_MEM
iveresov@201
# define LGRP_RSRC_MEM           1       /* memory resources */
iveresov@201
#endif
iveresov@201
duke@0
// Some more macros from sys/mman.h that are not present in Solaris 8.
duke@0
duke@0
#ifndef MAX_MEMINFO_CNT
duke@0
/*
duke@0
 * info_req request type definitions for meminfo
duke@0
 * request types starting with MEMINFO_V are used for Virtual addresses
duke@0
 * and should not be mixed with MEMINFO_PLGRP which is targeted for Physical
duke@0
 * addresses
duke@0
 */
duke@0
# define MEMINFO_SHIFT           16
duke@0
# define MEMINFO_MASK            (0xFF << MEMINFO_SHIFT)
duke@0
# define MEMINFO_VPHYSICAL       (0x01 << MEMINFO_SHIFT) /* get physical addr */
duke@0
# define MEMINFO_VLGRP           (0x02 << MEMINFO_SHIFT) /* get lgroup */
duke@0
# define MEMINFO_VPAGESIZE       (0x03 << MEMINFO_SHIFT) /* size of phys page */
duke@0
# define MEMINFO_VREPLCNT        (0x04 << MEMINFO_SHIFT) /* no. of replica */
duke@0
# define MEMINFO_VREPL           (0x05 << MEMINFO_SHIFT) /* physical replica */
duke@0
# define MEMINFO_VREPL_LGRP      (0x06 << MEMINFO_SHIFT) /* lgrp of replica */
duke@0
# define MEMINFO_PLGRP           (0x07 << MEMINFO_SHIFT) /* lgroup for paddr */
duke@0
duke@0
/* maximum number of addresses meminfo() can process at a time */
duke@0
# define MAX_MEMINFO_CNT 256
duke@0
duke@0
/* maximum number of request types */
duke@0
# define MAX_MEMINFO_REQ 31
duke@0
#endif
duke@0
duke@0
// see thr_setprio(3T) for the basis of these numbers
duke@0
#define MinimumPriority 0
duke@0
#define NormalPriority  64
duke@0
#define MaximumPriority 127
duke@0
duke@0
// Values for ThreadPriorityPolicy == 1
duke@0
int prio_policy1[MaxPriority+1] = { -99999, 0, 16, 32, 48, 64,
duke@0
                                        80, 96, 112, 124, 127 };
duke@0
duke@0
// System parameters used internally
duke@0
static clock_t clock_tics_per_sec = 100;
duke@0
duke@0
// For diagnostics to print a message once. see run_periodic_checks
duke@0
static bool check_addr0_done = false;
duke@0
static sigset_t check_signal_done;
duke@0
static bool check_signals = true;
duke@0
duke@0
address os::Solaris::handler_start;  // start pc of thr_sighndlrinfo
duke@0
address os::Solaris::handler_end;    // end pc of thr_sighndlrinfo
duke@0
duke@0
address os::Solaris::_main_stack_base = NULL;  // 4352906 workaround
duke@0
duke@0
duke@0
// "default" initializers for missing libc APIs
duke@0
extern "C" {
duke@0
  static int lwp_mutex_init(mutex_t *mx, int scope, void *arg) { memset(mx, 0, sizeof(mutex_t)); return 0; }
duke@0
  static int lwp_mutex_destroy(mutex_t *mx)                 { return 0; }
duke@0
duke@0
  static int lwp_cond_init(cond_t *cv, int scope, void *arg){ memset(cv, 0, sizeof(cond_t)); return 0; }
duke@0
  static int lwp_cond_destroy(cond_t *cv)                   { return 0; }
duke@0
}
duke@0
duke@0
// "default" initializers for pthread-based synchronization
duke@0
extern "C" {
duke@0
  static int pthread_mutex_default_init(mutex_t *mx, int scope, void *arg) { memset(mx, 0, sizeof(mutex_t)); return 0; }
duke@0
  static int pthread_cond_default_init(cond_t *cv, int scope, void *arg){ memset(cv, 0, sizeof(cond_t)); return 0; }
duke@0
}
duke@0
duke@0
// Thread Local Storage
duke@0
// This is common to all Solaris platforms so it is defined here,
duke@0
// in this common file.
duke@0
// The declarations are in the os_cpu threadLS*.hpp files.
duke@0
//
duke@0
// Static member initialization for TLS
duke@0
Thread* ThreadLocalStorage::_get_thread_cache[ThreadLocalStorage::_pd_cache_size] = {NULL};
duke@0
duke@0
#ifndef PRODUCT
duke@0
#define _PCT(n,d)       ((100.0*(double)(n))/(double)(d))
duke@0
duke@0
int ThreadLocalStorage::_tcacheHit = 0;
duke@0
int ThreadLocalStorage::_tcacheMiss = 0;
duke@0
duke@0
void ThreadLocalStorage::print_statistics() {
duke@0
  int total = _tcacheMiss+_tcacheHit;
duke@0
  tty->print_cr("Thread cache hits %d misses %d total %d percent %f\n",
duke@0
                _tcacheHit, _tcacheMiss, total, _PCT(_tcacheHit, total));
duke@0
}
duke@0
#undef _PCT
duke@0
#endif // PRODUCT
duke@0
duke@0
Thread* ThreadLocalStorage::get_thread_via_cache_slowly(uintptr_t raw_id,
duke@0
                                                        int index) {
duke@0
  Thread *thread = get_thread_slow();
duke@0
  if (thread != NULL) {
duke@0
    address sp = os::current_stack_pointer();
duke@0
    guarantee(thread->_stack_base == NULL ||
duke@0
              (sp <= thread->_stack_base &&
duke@0
                 sp >= thread->_stack_base - thread->_stack_size) ||
duke@0
               is_error_reported(),
duke@0
              "sp must be inside of selected thread stack");
duke@0
duke@0
    thread->_self_raw_id = raw_id;  // mark for quick retrieval
duke@0
    _get_thread_cache[ index ] = thread;
duke@0
  }
duke@0
  return thread;
duke@0
}
duke@0
duke@0
duke@0
static const double all_zero[ sizeof(Thread) / sizeof(double) + 1 ] = {0};
duke@0
#define NO_CACHED_THREAD ((Thread*)all_zero)
duke@0
duke@0
void ThreadLocalStorage::pd_set_thread(Thread* thread) {
duke@0
duke@0
  // Store the new value before updating the cache to prevent a race
duke@0
  // between get_thread_via_cache_slowly() and this store operation.
duke@0
  os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread);
duke@0
duke@0
  // Update thread cache with new thread if setting on thread create,
duke@0
  // or NO_CACHED_THREAD (zeroed) thread if resetting thread on exit.
duke@0
  uintptr_t raw = pd_raw_thread_id();
duke@0
  int ix = pd_cache_index(raw);
duke@0
  _get_thread_cache[ix] = thread == NULL ? NO_CACHED_THREAD : thread;
duke@0
}
duke@0
duke@0
void ThreadLocalStorage::pd_init() {
duke@0
  for (int i = 0; i < _pd_cache_size; i++) {
duke@0
    _get_thread_cache[i] = NO_CACHED_THREAD;
duke@0
  }
duke@0
}
duke@0
duke@0
// Invalidate all the caches (happens to be the same as pd_init).
duke@0
void ThreadLocalStorage::pd_invalidate_all() { pd_init(); }
duke@0
duke@0
#undef NO_CACHED_THREAD
duke@0
duke@0
// END Thread Local Storage
duke@0
duke@0
static inline size_t adjust_stack_size(address base, size_t size) {
duke@0
  if ((ssize_t)size < 0) {
duke@0
    // 4759953: Compensate for ridiculous stack size.
duke@0
    size = max_intx;
duke@0
  }
duke@0
  if (size > (size_t)base) {
duke@0
    // 4812466: Make sure size doesn't allow the stack to wrap the address space.
duke@0
    size = (size_t)base;
duke@0
  }
duke@0
  return size;
duke@0
}
duke@0
duke@0
static inline stack_t get_stack_info() {
duke@0
  stack_t st;
duke@0
  int retval = thr_stksegment(&st);
duke@0
  st.ss_size = adjust_stack_size((address)st.ss_sp, st.ss_size);
duke@0
  assert(retval == 0, "incorrect return value from thr_stksegment");
duke@0
  assert((address)&st < (address)st.ss_sp, "Invalid stack base returned");
duke@0
  assert((address)&st > (address)st.ss_sp-st.ss_size, "Invalid stack size returned");
duke@0
  return st;
duke@0
}
duke@0
duke@0
address os::current_stack_base() {
duke@0
  int r = thr_main() ;
duke@0
  guarantee (r == 0 || r == 1, "CR6501650 or CR6493689") ;
duke@0
  bool is_primordial_thread = r;
duke@0
duke@0
  // Workaround 4352906, avoid calls to thr_stksegment by
duke@0
  // thr_main after the first one (it looks like we trash
duke@0
  // some data, causing the value for ss_sp to be incorrect).
duke@0
  if (!is_primordial_thread || os::Solaris::_main_stack_base == NULL) {
duke@0
    stack_t st = get_stack_info();
duke@0
    if (is_primordial_thread) {
duke@0
      // cache initial value of stack base
duke@0
      os::Solaris::_main_stack_base = (address)st.ss_sp;
duke@0
    }
duke@0
    return (address)st.ss_sp;
duke@0
  } else {
duke@0
    guarantee(os::Solaris::_main_stack_base != NULL, "Attempt to use null cached stack base");
duke@0
    return os::Solaris::_main_stack_base;
duke@0
  }
duke@0
}
duke@0
duke@0
size_t os::current_stack_size() {
duke@0
  size_t size;
duke@0
duke@0
  int r = thr_main() ;
duke@0
  guarantee (r == 0 || r == 1, "CR6501650 or CR6493689") ;
duke@0
  if(!r) {
duke@0
    size = get_stack_info().ss_size;
duke@0
  } else {
duke@0
    struct rlimit limits;
duke@0
    getrlimit(RLIMIT_STACK, &limits);
duke@0
    size = adjust_stack_size(os::Solaris::_main_stack_base, (size_t)limits.rlim_cur);
duke@0
  }
duke@0
  // base may not be page aligned
duke@0
  address base = current_stack_base();
duke@0
  address bottom = (address)align_size_up((intptr_t)(base - size), os::vm_page_size());;
duke@0
  return (size_t)(base - bottom);
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
// interruptible infrastructure
duke@0
duke@0
// setup_interruptible saves the thread state before going into an
duke@0
// interruptible system call.
duke@0
// The saved state is used to restore the thread to
duke@0
// its former state whether or not an interrupt is received.
duke@0
// Used by classloader os::read
duke@0
// hpi calls skip this layer and stay in _thread_in_native
duke@0
duke@0
void os::Solaris::setup_interruptible(JavaThread* thread) {
duke@0
duke@0
  JavaThreadState thread_state = thread->thread_state();
duke@0
duke@0
  assert(thread_state != _thread_blocked, "Coming from the wrong thread");
duke@0
  assert(thread_state != _thread_in_native, "Native threads skip setup_interruptible");
duke@0
  OSThread* osthread = thread->osthread();
duke@0
  osthread->set_saved_interrupt_thread_state(thread_state);
duke@0
  thread->frame_anchor()->make_walkable(thread);
duke@0
  ThreadStateTransition::transition(thread, thread_state, _thread_blocked);
duke@0
}
duke@0
duke@0
// Version of setup_interruptible() for threads that are already in
duke@0
// _thread_blocked. Used by os_sleep().
duke@0
void os::Solaris::setup_interruptible_already_blocked(JavaThread* thread) {
duke@0
  thread->frame_anchor()->make_walkable(thread);
duke@0
}
duke@0
duke@0
JavaThread* os::Solaris::setup_interruptible() {
duke@0
  JavaThread* thread = (JavaThread*)ThreadLocalStorage::thread();
duke@0
  setup_interruptible(thread);
duke@0
  return thread;
duke@0
}
duke@0
duke@0
void os::Solaris::try_enable_extended_io() {
duke@0
  typedef int (*enable_extended_FILE_stdio_t)(int, int);
duke@0
duke@0
  if (!UseExtendedFileIO) {
duke@0
    return;
duke@0
  }
duke@0
duke@0
  enable_extended_FILE_stdio_t enabler =
duke@0
    (enable_extended_FILE_stdio_t) dlsym(RTLD_DEFAULT,
duke@0
                                         "enable_extended_FILE_stdio");
duke@0
  if (enabler) {
duke@0
    enabler(-1, -1);
duke@0
  }
duke@0
}
duke@0
duke@0
duke@0
#ifdef ASSERT
duke@0
duke@0
JavaThread* os::Solaris::setup_interruptible_native() {
duke@0
  JavaThread* thread = (JavaThread*)ThreadLocalStorage::thread();
duke@0
  JavaThreadState thread_state = thread->thread_state();
duke@0
  assert(thread_state == _thread_in_native, "Assumed thread_in_native");
duke@0
  return thread;
duke@0
}
duke@0
duke@0
void os::Solaris::cleanup_interruptible_native(JavaThread* thread) {
duke@0
  JavaThreadState thread_state = thread->thread_state();
duke@0
  assert(thread_state == _thread_in_native, "Assumed thread_in_native");
duke@0
}
duke@0
#endif
duke@0
duke@0
// cleanup_interruptible reverses the effects of setup_interruptible
duke@0
// setup_interruptible_already_blocked() does not need any cleanup.
duke@0
duke@0
void os::Solaris::cleanup_interruptible(JavaThread* thread) {
duke@0
  OSThread* osthread = thread->osthread();
duke@0
duke@0
  ThreadStateTransition::transition(thread, _thread_blocked, osthread->saved_interrupt_thread_state());
duke@0
}
duke@0
duke@0
// I/O interruption related counters called in _INTERRUPTIBLE
duke@0
duke@0
void os::Solaris::bump_interrupted_before_count() {
duke@0
  RuntimeService::record_interrupted_before_count();
duke@0
}
duke@0
duke@0
void os::Solaris::bump_interrupted_during_count() {
duke@0
  RuntimeService::record_interrupted_during_count();
duke@0
}
duke@0
duke@0
static int _processors_online = 0;
duke@0
duke@0
         jint os::Solaris::_os_thread_limit = 0;
duke@0
volatile jint os::Solaris::_os_thread_count = 0;
duke@0
duke@0
julong os::available_memory() {
duke@0
  return Solaris::available_memory();
duke@0
}
duke@0
duke@0
julong os::Solaris::available_memory() {
duke@0
  return (julong)sysconf(_SC_AVPHYS_PAGES) * os::vm_page_size();
duke@0
}
duke@0
duke@0
julong os::Solaris::_physical_memory = 0;
duke@0
duke@0
julong os::physical_memory() {
duke@0
   return Solaris::physical_memory();
duke@0
}
duke@0
duke@0
julong os::allocatable_physical_memory(julong size) {
duke@0
#ifdef _LP64
duke@0
   return size;
duke@0
#else
duke@0
   julong result = MIN2(size, (julong)3835*M);
duke@0
   if (!is_allocatable(result)) {
duke@0
     // Memory allocations will be aligned but the alignment
duke@0
     // is not known at this point.  Alignments will
duke@0
     // be at most to LargePageSizeInBytes.  Protect
duke@0
     // allocations from alignments up to illegal
duke@0
     // values. If at this point 2G is illegal.
duke@0
     julong reasonable_size = (julong)2*G - 2 * LargePageSizeInBytes;
duke@0
     result =  MIN2(size, reasonable_size);
duke@0
   }
duke@0
   return result;
duke@0
#endif
duke@0
}
duke@0
duke@0
static hrtime_t first_hrtime = 0;
duke@0
static const hrtime_t hrtime_hz = 1000*1000*1000;
duke@0
const int LOCK_BUSY = 1;
duke@0
const int LOCK_FREE = 0;
duke@0
const int LOCK_INVALID = -1;
duke@0
static volatile hrtime_t max_hrtime = 0;
duke@0
static volatile int max_hrtime_lock = LOCK_FREE;     // Update counter with LSB as lock-in-progress
duke@0
duke@0
duke@0
void os::Solaris::initialize_system_info() {
phh@1352
  set_processor_count(sysconf(_SC_NPROCESSORS_CONF));
duke@0
  _processors_online = sysconf (_SC_NPROCESSORS_ONLN);
duke@0
  _physical_memory = (julong)sysconf(_SC_PHYS_PAGES) * (julong)sysconf(_SC_PAGESIZE);
duke@0
}
duke@0
duke@0
int os::active_processor_count() {
duke@0
  int online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
duke@0
  pid_t pid = getpid();
duke@0
  psetid_t pset = PS_NONE;
xlu@444
  // Are we running in a processor set or is there any processor set around?
duke@0
  if (pset_bind(PS_QUERY, P_PID, pid, &pset) == 0) {
xlu@444
    uint_t pset_cpus;
xlu@444
    // Query the number of cpus available to us.
xlu@444
    if (pset_info(pset, NULL, &pset_cpus, NULL) == 0) {
xlu@444
      assert(pset_cpus > 0 && pset_cpus <= online_cpus, "sanity check");
xlu@444
      _processors_online = pset_cpus;
xlu@444
      return pset_cpus;
duke@0
    }
duke@0
  }
duke@0
  // Otherwise return number of online cpus
duke@0
  return online_cpus;
duke@0
}
duke@0
duke@0
static bool find_processors_in_pset(psetid_t        pset,
duke@0
                                    processorid_t** id_array,
duke@0
                                    uint_t*         id_length) {
duke@0
  bool result = false;
duke@0
  // Find the number of processors in the processor set.
duke@0
  if (pset_info(pset, NULL, id_length, NULL) == 0) {
duke@0
    // Make up an array to hold their ids.
duke@0
    *id_array = NEW_C_HEAP_ARRAY(processorid_t, *id_length);
duke@0
    // Fill in the array with their processor ids.
duke@0
    if (pset_info(pset, NULL, id_length, *id_array) == 0) {
duke@0
      result = true;
duke@0
    }
duke@0
  }
duke@0
  return result;
duke@0
}
duke@0
duke@0
// Callers of find_processors_online() must tolerate imprecise results --
duke@0
// the system configuration can change asynchronously because of DR
duke@0
// or explicit psradm operations.
duke@0
//
duke@0
// We also need to take care that the loop (below) terminates as the
duke@0
// number of processors online can change between the _SC_NPROCESSORS_ONLN
duke@0
// request and the loop that builds the list of processor ids.   Unfortunately
duke@0
// there's no reliable way to determine the maximum valid processor id,
duke@0
// so we use a manifest constant, MAX_PROCESSOR_ID, instead.  See p_online
duke@0
// man pages, which claim the processor id set is "sparse, but
duke@0
// not too sparse".  MAX_PROCESSOR_ID is used to ensure that we eventually
duke@0
// exit the loop.
duke@0
//
duke@0
// In the future we'll be able to use sysconf(_SC_CPUID_MAX), but that's
duke@0
// not available on S8.0.
duke@0
duke@0
static bool find_processors_online(processorid_t** id_array,
duke@0
                                   uint*           id_length) {
duke@0
  const processorid_t MAX_PROCESSOR_ID = 100000 ;
duke@0
  // Find the number of processors online.
duke@0
  *id_length = sysconf(_SC_NPROCESSORS_ONLN);
duke@0
  // Make up an array to hold their ids.
duke@0
  *id_array = NEW_C_HEAP_ARRAY(processorid_t, *id_length);
duke@0
  // Processors need not be numbered consecutively.
duke@0
  long found = 0;
duke@0
  processorid_t next = 0;
duke@0
  while (found < *id_length && next < MAX_PROCESSOR_ID) {
duke@0
    processor_info_t info;
duke@0
    if (processor_info(next, &info) == 0) {
duke@0
      // NB, PI_NOINTR processors are effectively online ...
duke@0
      if (info.pi_state == P_ONLINE || info.pi_state == P_NOINTR) {
duke@0
        (*id_array)[found] = next;
duke@0
        found += 1;
duke@0
      }
duke@0
    }
duke@0
    next += 1;
duke@0
  }
duke@0
  if (found < *id_length) {
duke@0
      // The loop above didn't identify the expected number of processors.
duke@0
      // We could always retry the operation, calling sysconf(_SC_NPROCESSORS_ONLN)
duke@0
      // and re-running the loop, above, but there's no guarantee of progress
duke@0
      // if the system configuration is in flux.  Instead, we just return what
duke@0
      // we've got.  Note that in the worst case find_processors_online() could
duke@0
      // return an empty set.  (As a fall-back in the case of the empty set we
duke@0
      // could just return the ID of the current processor).
duke@0
      *id_length = found ;
duke@0
  }
duke@0
duke@0
  return true;
duke@0
}
duke@0
duke@0
static bool assign_distribution(processorid_t* id_array,
duke@0
                                uint           id_length,
duke@0
                                uint*          distribution,
duke@0
                                uint           distribution_length) {
duke@0
  // We assume we can assign processorid_t's to uint's.
duke@0
  assert(sizeof(processorid_t) == sizeof(uint),
duke@0
         "can't convert processorid_t to uint");
duke@0
  // Quick check to see if we won't succeed.
duke@0
  if (id_length < distribution_length) {
duke@0
    return false;
duke@0
  }
duke@0
  // Assign processor ids to the distribution.
duke@0
  // Try to shuffle processors to distribute work across boards,
duke@0
  // assuming 4 processors per board.
duke@0
  const uint processors_per_board = ProcessDistributionStride;
duke@0
  // Find the maximum processor id.
duke@0
  processorid_t max_id = 0;
duke@0
  for (uint m = 0; m < id_length; m += 1) {
duke@0
    max_id = MAX2(max_id, id_array[m]);
duke@0
  }
duke@0
  // The next id, to limit loops.
duke@0
  const processorid_t limit_id = max_id + 1;
duke@0
  // Make up markers for available processors.
duke@0
  bool* available_id = NEW_C_HEAP_ARRAY(bool, limit_id);
duke@0
  for (uint c = 0; c < limit_id; c += 1) {
duke@0
    available_id[c] = false;
duke@0
  }
duke@0
  for (uint a = 0; a < id_length; a += 1) {
duke@0
    available_id[id_array[a]] = true;
duke@0
  }
duke@0
  // Step by "boards", then by "slot", copying to "assigned".
duke@0
  // NEEDS_CLEANUP: The assignment of processors should be stateful,
duke@0
  //                remembering which processors have been assigned by
duke@0
  //                previous calls, etc., so as to distribute several
duke@0
  //                independent calls of this method.  What we'd like is
duke@0
  //                It would be nice to have an API that let us ask
duke@0
  //                how many processes are bound to a processor,
duke@0
  //                but we don't have that, either.
duke@0
  //                In the short term, "board" is static so that
duke@0
  //                subsequent distributions don't all start at board 0.
duke@0
  static uint board = 0;
duke@0
  uint assigned = 0;
duke@0
  // Until we've found enough processors ....
duke@0
  while (assigned < distribution_length) {
duke@0
    // ... find the next available processor in the board.
duke@0
    for (uint slot = 0; slot < processors_per_board; slot += 1) {
duke@0
      uint try_id = board * processors_per_board + slot;
duke@0
      if ((try_id < limit_id) && (available_id[try_id] == true)) {
duke@0
        distribution[assigned] = try_id;
duke@0
        available_id[try_id] = false;
duke@0
        assigned += 1;
duke@0
        break;
duke@0
      }
duke@0
    }
duke@0
    board += 1;
duke@0
    if (board * processors_per_board + 0 >= limit_id) {
duke@0
      board = 0;
duke@0
    }
duke@0
  }
duke@0
  if (available_id != NULL) {
duke@0
    FREE_C_HEAP_ARRAY(bool, available_id);
duke@0
  }
duke@0
  return true;
duke@0
}
duke@0
duke@0
bool os::distribute_processes(uint length, uint* distribution) {
duke@0
  bool result = false;
duke@0
  // Find the processor id's of all the available CPUs.
duke@0
  processorid_t* id_array  = NULL;
duke@0
  uint           id_length = 0;
duke@0
  // There are some races between querying information and using it,
duke@0
  // since processor sets can change dynamically.
duke@0
  psetid_t pset = PS_NONE;
duke@0
  // Are we running in a processor set?
duke@0
  if ((pset_bind(PS_QUERY, P_PID, P_MYID, &pset) == 0) && pset != PS_NONE) {
duke@0
    result = find_processors_in_pset(pset, &id_array, &id_length);
duke@0
  } else {
duke@0
    result = find_processors_online(&id_array, &id_length);
duke@0
  }
duke@0
  if (result == true) {
duke@0
    if (id_length >= length) {
duke@0
      result = assign_distribution(id_array, id_length, distribution, length);
duke@0
    } else {
duke@0
      result = false;
duke@0
    }
duke@0
  }
duke@0
  if (id_array != NULL) {
duke@0
    FREE_C_HEAP_ARRAY(processorid_t, id_array);
duke@0
  }
duke@0
  return result;
duke@0
}
duke@0
duke@0
bool os::bind_to_processor(uint processor_id) {
duke@0
  // We assume that a processorid_t can be stored in a uint.
duke@0
  assert(sizeof(uint) == sizeof(processorid_t),
duke@0
         "can't convert uint to processorid_t");
duke@0
  int bind_result =
duke@0
    processor_bind(P_LWPID,                       // bind LWP.
duke@0
                   P_MYID,                        // bind current LWP.
duke@0
                   (processorid_t) processor_id,  // id.
duke@0
                   NULL);                         // don't return old binding.
duke@0
  return (bind_result == 0);
duke@0
}
duke@0
duke@0
bool os::getenv(const char* name, char* buffer, int len) {
duke@0
  char* val = ::getenv( name );
duke@0
  if ( val == NULL
duke@0
  ||   strlen(val) + 1  >  len ) {
duke@0
    if (len > 0)  buffer[0] = 0; // return a null string
duke@0
    return false;
duke@0
  }
duke@0
  strcpy( buffer, val );
duke@0
  return true;
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
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 free(p) FREE_C_HEAP_ARRAY(char, p)
duke@0
#define getenv(n) ::getenv(n)
duke@0
duke@0
#define EXTENSIONS_DIR  "/lib/ext"
duke@0
#define ENDORSED_DIR    "/lib/endorsed"
duke@0
#define COMMON_DIR      "/usr/jdk/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
    {
duke@0
      // Use dlinfo() to determine the correct java.library.path.
duke@0
      //
duke@0
      // If we're launched by the Java launcher, and the user
duke@0
      // does not set java.library.path explicitly on the commandline,
duke@0
      // the Java launcher sets LD_LIBRARY_PATH for us and unsets
duke@0
      // LD_LIBRARY_PATH_32 and LD_LIBRARY_PATH_64.  In this case
duke@0
      // dlinfo returns LD_LIBRARY_PATH + crle settings (including
duke@0
      // /usr/lib), which is exactly what we want.
duke@0
      //
duke@0
      // If the user does set java.library.path, it completely
duke@0
      // overwrites this setting, and always has.
duke@0
      //
duke@0
      // If we're not launched by the Java launcher, we may
duke@0
      // get here with any/all of the LD_LIBRARY_PATH[_32|64]
duke@0
      // settings.  Again, dlinfo does exactly what we want.
duke@0
duke@0
      Dl_serinfo     _info, *info = &_info;
duke@0
      Dl_serpath     *path;
duke@0
      char*          library_path;
duke@0
      char           *common_path;
duke@0
      int            i;
duke@0
duke@0
      // determine search path count and required buffer size
duke@0
      if (dlinfo(RTLD_SELF, RTLD_DI_SERINFOSIZE, (void *)info) == -1) {
duke@0
        vm_exit_during_initialization("dlinfo SERINFOSIZE request", dlerror());
duke@0
      }
duke@0
duke@0
      // allocate new buffer and initialize
duke@0
      info = (Dl_serinfo*)malloc(_info.dls_size);
duke@0
      if (info == NULL) {
duke@0
        vm_exit_out_of_memory(_info.dls_size,
duke@0
                              "init_system_properties_values info");
duke@0
      }
duke@0
      info->dls_size = _info.dls_size;
duke@0
      info->dls_cnt = _info.dls_cnt;
duke@0
duke@0
      // obtain search path information
duke@0
      if (dlinfo(RTLD_SELF, RTLD_DI_SERINFO, (void *)info) == -1) {
duke@0
        free(info);
duke@0
        vm_exit_during_initialization("dlinfo SERINFO request", dlerror());
duke@0
      }
duke@0
duke@0
      path = &info->dls_serpath[0];
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 Solaris 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/jdk/packages is added here.
duke@0
duke@0
      // Determine the actual CPU architecture.
duke@0
      char cpu_arch[12];
duke@0
      sysinfo(SI_ARCHITECTURE, cpu_arch, sizeof(cpu_arch));
duke@0
#ifdef _LP64
duke@0
      // If we are a 64-bit vm, perform the following translations:
duke@0
      //   sparc   -> sparcv9
duke@0
      //   i386    -> amd64
duke@0
      if (strcmp(cpu_arch, "sparc") == 0)
duke@0
        strcat(cpu_arch, "v9");
duke@0
      else if (strcmp(cpu_arch, "i386") == 0)
duke@0
        strcpy(cpu_arch, "amd64");
duke@0
#endif
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.
duke@0
      size_t bufsize = sizeof(COMMON_DIR) + sizeof("/lib/") + strlen(cpu_arch);
duke@0
      common_path = malloc(bufsize);
duke@0
      if (common_path == NULL) {
duke@0
        free(info);
duke@0
        vm_exit_out_of_memory(bufsize,
duke@0
                              "init_system_properties_values common_path");
duke@0
      }
duke@0
      sprintf(common_path, COMMON_DIR "/lib/%s", cpu_arch);
duke@0
duke@0
      // struct size is more than sufficient for the path components obtained
duke@0
      // through the dlinfo() call, so only add additional space for the path
duke@0
      // components explicitly added here.
duke@0
      bufsize = info->dls_size + strlen(common_path);
duke@0
      library_path = malloc(bufsize);
duke@0
      if (library_path == NULL) {
duke@0
        free(info);
duke@0
        free(common_path);
duke@0
        vm_exit_out_of_memory(bufsize,
duke@0
                              "init_system_properties_values library_path");
duke@0
      }
duke@0
      library_path[0] = '\0';
duke@0
duke@0
      // Construct the desired Java library path from the linker's library
duke@0
      // search path.
duke@0
      //
duke@0
      // For compatibility, it is optimal that we insert the additional path
duke@0
      // components specific to the Java VM after those components specified
duke@0
      // in LD_LIBRARY_PATH (if any) but before those added by the ld.so
duke@0
      // infrastructure.
duke@0
      if (info->dls_cnt == 0) { // Not sure this can happen, but allow for it
duke@0
        strcpy(library_path, common_path);
duke@0
      } else {
duke@0
        int inserted = 0;
duke@0
        for (i = 0; i < info->dls_cnt; i++, path++) {
duke@0
          uint_t flags = path->dls_flags & LA_SER_MASK;
duke@0
          if (((flags & LA_SER_LIBPATH) == 0) && !inserted) {
duke@0
            strcat(library_path, common_path);
duke@0
            strcat(library_path, os::path_separator());
duke@0
            inserted = 1;
duke@0
          }
duke@0
          strcat(library_path, path->dls_name);
duke@0
          strcat(library_path, os::path_separator());
duke@0
        }
duke@0
        // eliminate trailing path separator
duke@0
        library_path[strlen(library_path)-1] = '\0';
duke@0
      }
duke@0
duke@0
      // happens before argument parsing - can't use a trace flag
duke@0
      // tty->print_raw("init_system_properties_values: native lib path: ");
duke@0
      // tty->print_raw_cr(library_path);
duke@0
duke@0
      // callee copies into its own buffer
duke@0
      Arguments::set_library_path(library_path);
duke@0
duke@0
      free(common_path);
duke@0
      free(library_path);
duke@0
      free(info);
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 = (char *) malloc(strlen(Arguments::get_java_home()) +
duke@0
            sizeof(EXTENSIONS_DIR) + sizeof(COMMON_DIR) +
duke@0
            sizeof(EXTENSIONS_DIR));
duke@0
        sprintf(buf, "%s" EXTENSIONS_DIR ":" COMMON_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 = 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 free
duke@0
#undef getenv
duke@0
#undef EXTENSIONS_DIR
duke@0
#undef ENDORSED_DIR
duke@0
#undef COMMON_DIR
duke@0
duke@0
}
duke@0
duke@0
void os::breakpoint() {
duke@0
  BREAKPOINT;
duke@0
}
duke@0
duke@0
bool os::obsolete_option(const JavaVMOption *option)
duke@0
{
duke@0
  if (!strncmp(option->optionString, "-Xt", 3)) {
duke@0
    return true;
duke@0
  } else if (!strncmp(option->optionString, "-Xtm", 4)) {
duke@0
    return true;
duke@0
  } else if (!strncmp(option->optionString, "-Xverifyheap", 12)) {
duke@0
    return true;
duke@0
  } else if (!strncmp(option->optionString, "-Xmaxjitcodesize", 16)) {
duke@0
    return true;
duke@0
  }
duke@0
  return false;
duke@0
}
duke@0
duke@0
bool os::Solaris::valid_stack_address(Thread* thread, address sp) {
duke@0
  address  stackStart  = (address)thread->stack_base();
duke@0
  address  stackEnd    = (address)(stackStart - (address)thread->stack_size());
duke@0
  if (sp < stackStart && sp >= stackEnd ) return true;
duke@0
  return false;
duke@0
}
duke@0
duke@0
extern "C" void breakpoint() {
duke@0
  // use debugger to set breakpoint here
duke@0
}
duke@0
duke@0
// Returns an estimate of the current stack pointer. Result must be guaranteed to
duke@0
// point into the calling threads stack, and be no lower than the current stack
duke@0
// pointer.
duke@0
address os::current_stack_pointer() {
duke@0
  volatile int dummy;
duke@0
  address sp = (address)&dummy + 8;     // %%%% need to confirm if this is right
duke@0
  return sp;
duke@0
}
duke@0
duke@0
static thread_t main_thread;
duke@0
duke@0
// Thread start routine for all new Java threads
duke@0
extern "C" void* java_start(void* thread_addr) {
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
  int prio;
duke@0
  Thread* thread = (Thread*)thread_addr;
duke@0
  OSThread* osthr = thread->osthread();
duke@0
duke@0
  osthr->set_lwp_id( _lwp_self() );  // Store lwp in case we are bound
duke@0
  thread->_schedctl = (void *) schedctl_init () ;
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 the creator called set priority before we started,
duke@0
  // we need to call set priority now that we have an lwp.
duke@0
  // Get the priority from libthread and set the priority
duke@0
  // for the new Solaris lwp.
duke@0
  if ( osthr->thread_id() != -1 ) {
duke@0
    if ( UseThreadPriorities ) {
duke@0
      thr_getprio(osthr->thread_id(), &prio);
duke@0
      if (ThreadPriorityVerbose) {
duke@0
        tty->print_cr("Starting Thread " INTPTR_FORMAT ", LWP is " INTPTR_FORMAT ", setting priority: %d\n",
duke@0
                      osthr->thread_id(), osthr->lwp_id(), prio );
duke@0
      }
duke@0
      os::set_native_priority(thread, prio);
duke@0
    }
duke@0
  } else if (ThreadPriorityVerbose) {
duke@0
    warning("Can't set priority in _start routine, thread id hasn't been set\n");
duke@0
  }
duke@0
duke@0
  assert(osthr->get_state() == RUNNABLE, "invalid os thread state");
duke@0
duke@0
  // initialize signal mask for this thread
duke@0
  os::Solaris::hotspot_sigmask(thread);
duke@0
duke@0
  thread->run();
duke@0
duke@0
  // One less thread is executing
duke@0
  // When the VMThread gets here, the main thread may have already exited
duke@0
  // which frees the CodeHeap containing the Atomic::dec code
duke@0
  if (thread != VMThread::vm_thread() && VMThread::vm_thread() != NULL) {
duke@0
    Atomic::dec(&os::Solaris::_os_thread_count);
duke@0
  }
duke@0
duke@0
  if (UseDetachedThreads) {
duke@0
    thr_exit(NULL);
duke@0
    ShouldNotReachHere();
duke@0
  }
duke@0
  return NULL;
duke@0
}
duke@0
duke@0
static OSThread* create_os_thread(Thread* thread, thread_t thread_id) {
duke@0
  // Allocate the OSThread object
duke@0
  OSThread* osthread = new OSThread(NULL, NULL);
duke@0
  if (osthread == NULL) return NULL;
duke@0
duke@0
  // Store info on the Solaris thread into the OSThread
duke@0
  osthread->set_thread_id(thread_id);
duke@0
  osthread->set_lwp_id(_lwp_self());
duke@0
  thread->_schedctl = (void *) schedctl_init () ;
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 ( ThreadPriorityVerbose ) {
duke@0
    tty->print_cr("In create_os_thread, Thread " INTPTR_FORMAT ", LWP is " INTPTR_FORMAT "\n",
duke@0
                  osthread->thread_id(), osthread->lwp_id() );
duke@0
  }
duke@0
duke@0
  // Initial thread state is INITIALIZED, not SUSPENDED
duke@0
  osthread->set_state(INITIALIZED);
duke@0
duke@0
  return osthread;
duke@0
}
duke@0
duke@0
void os::Solaris::hotspot_sigmask(Thread* thread) {
duke@0
duke@0
  //Save caller's signal mask
duke@0
  sigset_t sigmask;
duke@0
  thr_sigsetmask(SIG_SETMASK, NULL, &sigmask);
duke@0
  OSThread *osthread = thread->osthread();
duke@0
  osthread->set_caller_sigmask(sigmask);
duke@0
duke@0
  thr_sigsetmask(SIG_UNBLOCK, os::Solaris::unblocked_signals(), NULL);
duke@0
  if (!ReduceSignalUsage) {
duke@0
    if (thread->is_VM_thread()) {
duke@0
      // Only the VM thread handles BREAK_SIGNAL ...
duke@0
      thr_sigsetmask(SIG_UNBLOCK, vm_signals(), NULL);
duke@0
    } else {
duke@0
      // ... all other threads block BREAK_SIGNAL
duke@0
      assert(!sigismember(vm_signals(), SIGINT), "SIGINT should not be blocked");
duke@0
      thr_sigsetmask(SIG_BLOCK, vm_signals(), NULL);
duke@0
    }
duke@0
  }
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
  OSThread* osthread = create_os_thread(thread, thr_self());
duke@0
  if (osthread == NULL) {
duke@0
     return false;
duke@0
  }
duke@0
duke@0
  // Initial thread state is RUNNABLE
duke@0
  osthread->set_state(RUNNABLE);
duke@0
  thread->set_osthread(osthread);
duke@0
duke@0
  // initialize signal mask for this thread
duke@0
  // and save the caller's signal mask
duke@0
  os::Solaris::hotspot_sigmask(thread);
duke@0
duke@0
  return true;
duke@0
}
duke@0
duke@0
bool os::create_main_thread(JavaThread* thread) {
duke@0
#ifdef ASSERT
duke@0
  thread->verify_not_published();
duke@0
#endif
duke@0
  if (_starting_thread == NULL) {
duke@0
    _starting_thread = create_os_thread(thread, main_thread);
duke@0
     if (_starting_thread == NULL) {
duke@0
        return false;
duke@0
     }
duke@0
  }
duke@0
duke@0
  // The primodial thread is runnable from the start
duke@0
  _starting_thread->set_state(RUNNABLE);
duke@0
duke@0
  thread->set_osthread(_starting_thread);
duke@0
duke@0
  // initialize signal mask for this thread
duke@0
  // and save the caller's signal mask
duke@0
  os::Solaris::hotspot_sigmask(thread);
duke@0
duke@0
  return true;
duke@0
}
duke@0
duke@0
// _T2_libthread is true if we believe we are running with the newer
duke@0
// SunSoft lwp/libthread.so (2.8 patch, 2.9 default)
duke@0
bool os::Solaris::_T2_libthread = false;
duke@0
duke@0
bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
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
  if ( ThreadPriorityVerbose ) {
duke@0
    char *thrtyp;
duke@0
    switch ( thr_type ) {
duke@0
      case vm_thread:
duke@0
        thrtyp = (char *)"vm";
duke@0
        break;
duke@0
      case cgc_thread:
duke@0
        thrtyp = (char *)"cgc";
duke@0
        break;
duke@0
      case pgc_thread:
duke@0
        thrtyp = (char *)"pgc";
duke@0
        break;
duke@0
      case java_thread:
duke@0
        thrtyp = (char *)"java";
duke@0
        break;
duke@0
      case compiler_thread:
duke@0
        thrtyp = (char *)"compiler";
duke@0
        break;
duke@0
      case watcher_thread:
duke@0
        thrtyp = (char *)"watcher";
duke@0
        break;
duke@0
      default:
duke@0
        thrtyp = (char *)"unknown";
duke@0
        break;
duke@0
    }
duke@0
    tty->print_cr("In create_thread, creating a %s thread\n", thrtyp);
duke@0
  }
duke@0
duke@0
  // Calculate stack size if it's not specified by caller.
duke@0
  if (stack_size == 0) {
duke@0
    // The default stack size 1M (2M for LP64).
duke@0
    stack_size = (BytesPerWord >> 2) * K * K;
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
  stack_size = MAX2(stack_size, os::Solaris::min_stack_allowed);
duke@0
duke@0
  // Initial state is ALLOCATED but not INITIALIZED
duke@0
  osthread->set_state(ALLOCATED);
duke@0
duke@0
  if (os::Solaris::_os_thread_count > os::Solaris::_os_thread_limit) {
duke@0
    // We got lots of threads. Check if we still have some address space left.
duke@0
    // Need to be at least 5Mb of unreserved address space. We do check by
duke@0
    // trying to reserve some.
duke@0
    const size_t VirtualMemoryBangSize = 20*K*K;
duke@0
    char* mem = os::reserve_memory(VirtualMemoryBangSize);
duke@0
    if (mem == NULL) {
duke@0
      delete osthread;
duke@0
      return false;
duke@0
    } else {
duke@0
      // Release the memory again
duke@0
      os::release_memory(mem, VirtualMemoryBangSize);
duke@0
    }
duke@0
  }
duke@0
duke@0
  // Setup osthread because the child thread may need it.
duke@0
  thread->set_osthread(osthread);
duke@0
duke@0
  // Create the Solaris thread
duke@0
  // explicit THR_BOUND for T2_libthread case in case
duke@0
  // that assumption is not accurate, but our alternate signal stack
duke@0
  // handling is based on it which must have bound threads
duke@0
  thread_t tid = 0;
duke@0
  long     flags = (UseDetachedThreads ? THR_DETACHED : 0) | THR_SUSPENDED
duke@0
                   | ((UseBoundThreads || os::Solaris::T2_libthread() ||
duke@0
                       (thr_type == vm_thread) ||
duke@0
                       (thr_type == cgc_thread) ||
duke@0
                       (thr_type == pgc_thread) ||
duke@0
                       (thr_type == compiler_thread && BackgroundCompilation)) ?
duke@0
                      THR_BOUND : 0);
duke@0
  int      status;
duke@0
duke@0
  // 4376845 -- libthread/kernel don't provide enough LWPs to utilize all CPUs.
duke@0
  //
duke@0
  // On multiprocessors systems, libthread sometimes under-provisions our
duke@0
  // process with LWPs.  On a 30-way systems, for instance, we could have
duke@0
  // 50 user-level threads in ready state and only 2 or 3 LWPs assigned
duke@0
  // to our process.  This can result in under utilization of PEs.
duke@0
  // I suspect the problem is related to libthread's LWP
duke@0
  // pool management and to the kernel's SIGBLOCKING "last LWP parked"
duke@0
  // upcall policy.
duke@0
  //
duke@0
  // The following code is palliative -- it attempts to ensure that our
duke@0
  // process has sufficient LWPs to take advantage of multiple PEs.
duke@0
  // Proper long-term cures include using user-level threads bound to LWPs
duke@0
  // (THR_BOUND) or using LWP-based synchronization.  Note that there is a
duke@0
  // slight timing window with respect to sampling _os_thread_count, but
duke@0
  // the race is benign.  Also, we should periodically recompute
duke@0
  // _processors_online as the min of SC_NPROCESSORS_ONLN and the
duke@0
  // the number of PEs in our partition.  You might be tempted to use
duke@0
  // THR_NEW_LWP here, but I'd recommend against it as that could
duke@0
  // result in undesirable growth of the libthread's LWP pool.
duke@0
  // The fix below isn't sufficient; for instance, it doesn't take into count
duke@0
  // LWPs parked on IO.  It does, however, help certain CPU-bound benchmarks.
duke@0
  //
duke@0
  // Some pathologies this scheme doesn't handle:
duke@0
  // *  Threads can block, releasing the LWPs.  The LWPs can age out.
duke@0
  //    When a large number of threads become ready again there aren't
duke@0
  //    enough LWPs available to service them.  This can occur when the
duke@0
  //    number of ready threads oscillates.
duke@0
  // *  LWPs/Threads park on IO, thus taking the LWP out of circulation.
duke@0
  //
duke@0
  // Finally, we should call thr_setconcurrency() periodically to refresh
duke@0
  // the LWP pool and thwart the LWP age-out mechanism.
duke@0
  // The "+3" term provides a little slop -- we want to slightly overprovision.
duke@0
duke@0
  if (AdjustConcurrency && os::Solaris::_os_thread_count < (_processors_online+3)) {
duke@0
    if (!(flags & THR_BOUND)) {
duke@0
      thr_setconcurrency (os::Solaris::_os_thread_count);       // avoid starvation
duke@0
    }
duke@0
  }
duke@0
  // Although this doesn't hurt, we should warn of undefined behavior
duke@0
  // when using unbound T1 threads with schedctl().  This should never
duke@0
  // happen, as the compiler and VM threads are always created bound
duke@0
  DEBUG_ONLY(
duke@0
      if ((VMThreadHintNoPreempt || CompilerThreadHintNoPreempt) &&
duke@0
          (!os::Solaris::T2_libthread() && (!(flags & THR_BOUND))) &&
duke@0
          ((thr_type == vm_thread) || (thr_type == cgc_thread) ||
duke@0
           (thr_type == pgc_thread) || (thr_type == compiler_thread && BackgroundCompilation))) {
duke@0
         warning("schedctl behavior undefined when Compiler/VM/GC Threads are Unbound");
duke@0
      }
duke@0
  );
duke@0
duke@0
duke@0
  // Mark that we don't have an lwp or thread id yet.
duke@0
  // In case we attempt to set the priority before the thread starts.
duke@0
  osthread->set_lwp_id(-1);
duke@0
  osthread->set_thread_id(-1);
duke@0
duke@0
  status = thr_create(NULL, stack_size, java_start, thread, flags, &tid);
duke@0
  if (status != 0) {
duke@0
    if (PrintMiscellaneous && (Verbose || WizardMode)) {
duke@0
      perror("os::create_thread");
duke@0
    }
duke@0
    thread->set_osthread(NULL);
duke@0
    // Need to clean up stuff we've allocated so far
duke@0
    delete osthread;
duke@0
    return false;
duke@0
  }
duke@0
duke@0
  Atomic::inc(&os::Solaris::_os_thread_count);
duke@0
duke@0
  // Store info on the Solaris thread into the OSThread
duke@0
  osthread->set_thread_id(tid);
duke@0
duke@0
  // Remember that we created this thread so we can set priority on it
duke@0
  osthread->set_vm_created();
duke@0
duke@0
  // Set the default thread priority otherwise use NormalPriority
duke@0
duke@0
  if ( UseThreadPriorities ) {
duke@0
     thr_setprio(tid, (DefaultThreadPriority == -1) ?
duke@0
                        java_to_os_priority[NormPriority] :
duke@0
                        DefaultThreadPriority);
duke@0
  }
duke@0
duke@0
  // Initial thread state is INITIALIZED, not SUSPENDED
duke@0
  osthread->set_state(INITIALIZED);
duke@0
duke@0
  // The thread is returned suspended (in state INITIALIZED), and is started higher up in the call chain
duke@0
  return true;
duke@0
}
duke@0
duke@0
/* defined for >= Solaris 10. This allows builds on earlier versions
duke@0
 *  of Solaris to take advantage of the newly reserved Solaris JVM signals
duke@0
 *  With SIGJVM1, SIGJVM2, INTERRUPT_SIGNAL is SIGJVM1, ASYNC_SIGNAL is SIGJVM2
duke@0
 *  and -XX:+UseAltSigs does nothing since these should have no conflict
duke@0
 */
duke@0
#if !defined(SIGJVM1)
duke@0
#define SIGJVM1 39
duke@0
#define SIGJVM2 40
duke@0
#endif
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
int os::Solaris::_SIGinterrupt = INTERRUPT_SIGNAL;
duke@0
int os::Solaris::_SIGasync = ASYNC_SIGNAL;
duke@0
duke@0
bool os::Solaris::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
// Note: SIGRTMIN is a macro that calls sysconf() so it will
duke@0
// dynamically detect SIGRTMIN value for the system at runtime, not buildtime
duke@0
static bool isJVM1available() {
duke@0
  return SIGJVM1 < SIGRTMIN;
duke@0
}
duke@0
duke@0
void os::Solaris::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
duke@0
  if (isJVM1available) {
duke@0
    os::Solaris::set_SIGinterrupt(SIGJVM1);
duke@0
    os::Solaris::set_SIGasync(SIGJVM2);
duke@0
  } else if (UseAltSigs) {
duke@0
    os::Solaris::set_SIGinterrupt(ALT_INTERRUPT_SIGNAL);
duke@0
    os::Solaris::set_SIGasync(ALT_ASYNC_SIGNAL);
duke@0
  } else {
duke@0
    os::Solaris::set_SIGinterrupt(INTERRUPT_SIGNAL);
duke@0
    os::Solaris::set_SIGasync(ASYNC_SIGNAL);
duke@0
  }
duke@0
duke@0
  sigaddset(&unblocked_sigs, os::Solaris::SIGinterrupt());
duke@0
  sigaddset(&unblocked_sigs, os::Solaris::SIGasync());
duke@0
duke@0
  if (!ReduceSignalUsage) {
duke@0
   if (!os::Solaris::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::Solaris::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::Solaris::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
  // For diagnostics only used in run_periodic_checks
duke@0
  sigemptyset(&check_signal_done);
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::Solaris::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::Solaris::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::Solaris::allowdebug_blocked_signals() {
duke@0
  assert(signal_sets_initialized, "Not initialized");
duke@0
  return &allowdebug_blocked_sigs;
duke@0
}
duke@0
duke@0
// First crack at OS-specific initialization, from inside the new thread.
duke@0
void os::initialize_thread() {
duke@0
  int r = thr_main() ;
duke@0
  guarantee (r == 0 || r == 1, "CR6501650 or CR6493689") ;
duke@0
  if (r) {
duke@0
    JavaThread* jt = (JavaThread *)Thread::current();
duke@0
    assert(jt != NULL,"Sanity check");
duke@0
    size_t stack_size;
duke@0
    address base = jt->stack_base();
duke@0
    if (Arguments::created_by_java_launcher()) {
duke@0
      // Use 2MB to allow for Solaris 7 64 bit mode.
duke@0
      stack_size = JavaThread::stack_size_at_create() == 0
duke@0
        ? 2048*K : JavaThread::stack_size_at_create();
duke@0
duke@0
      // There are rare cases when we may have already used more than
duke@0
      // the basic stack size allotment before this method is invoked.
duke@0
      // Attempt to allow for a normally sized java_stack.
duke@0
      size_t current_stack_offset = (size_t)(base - (address)&stack_size);
duke@0
      stack_size += ReservedSpace::page_align_size_down(current_stack_offset);
duke@0
    } else {
duke@0
      // 6269555: If we were not created by a Java launcher, i.e. if we are
duke@0
      // running embedded in a native application, treat the primordial thread
duke@0
      // as much like a native attached thread as possible.  This means using
duke@0
      // the current stack size from thr_stksegment(), unless it is too large
duke@0
      // to reliably setup guard pages.  A reasonable max size is 8MB.
duke@0
      size_t current_size = current_stack_size();
duke@0
      // This should never happen, but just in case....
duke@0
      if (current_size == 0) current_size = 2 * K * K;
duke@0
      stack_size = current_size > (8 * K * K) ? (8 * K * K) : current_size;
duke@0
    }
duke@0
    address bottom = (address)align_size_up((intptr_t)(base - stack_size), os::vm_page_size());;
duke@0
    stack_size = (size_t)(base - bottom);
duke@0
duke@0
    assert(stack_size > 0, "Stack size calculation problem");
duke@0
duke@0
    if (stack_size > jt->stack_size()) {
duke@0
      NOT_PRODUCT(
duke@0
        struct rlimit limits;
duke@0
        getrlimit(RLIMIT_STACK, &limits);
duke@0
        size_t size = adjust_stack_size(base, (size_t)limits.rlim_cur);
duke@0
        assert(size >= jt->stack_size(), "Stack size problem in main thread");
duke@0
      )
duke@0
      tty->print_cr(
duke@0
        "Stack size of %d Kb exceeds current limit of %d Kb.\n"
duke@0
        "(Stack sizes are rounded up to a multiple of the system page size.)\n"
duke@0
        "See limit(1) to increase the stack size limit.",
duke@0
        stack_size / K, jt->stack_size() / K);
duke@0
      vm_exit(1);
duke@0
    }
duke@0
    assert(jt->stack_size() >= stack_size,
duke@0
          "Attempt to map more stack than was allocated");
duke@0
    jt->set_stack_size(stack_size);
duke@0
  }
duke@0
duke@0
   // 5/22/01: Right now alternate signal stacks do not handle
duke@0
   // throwing stack overflow exceptions, see bug 4463178
duke@0
   // Until a fix is found for this, T2 will NOT imply alternate signal
duke@0
   // stacks.
duke@0
   // If using T2 libthread threads, install an alternate signal stack.
duke@0
   // Because alternate stacks associate with LWPs on Solaris,
duke@0
   // see sigaltstack(2), if using UNBOUND threads, or if UseBoundThreads
duke@0
   // we prefer to explicitly stack bang.
duke@0
   // If not using T2 libthread, but using UseBoundThreads any threads
duke@0
   // (primordial thread, jni_attachCurrentThread) we do not create,
duke@0
   // probably are not bound, therefore they can not have an alternate
duke@0
   // signal stack. Since our stack banging code is generated and
duke@0
   // is shared across threads, all threads must be bound to allow
duke@0
   // using alternate signal stacks.  The alternative is to interpose
duke@0
   // on _lwp_create to associate an alt sig stack with each LWP,
duke@0
   // and this could be a problem when the JVM is embedded.
duke@0
   // We would prefer to use alternate signal stacks with T2
duke@0
   // Since there is currently no accurate way to detect T2
duke@0
   // we do not. Assuming T2 when running T1 causes sig 11s or assertions
duke@0
   // on installing alternate signal stacks
duke@0
duke@0
duke@0
   // 05/09/03: removed alternate signal stack support for Solaris
duke@0
   // The alternate signal stack mechanism is no longer needed to
duke@0
   // handle stack overflow. This is now handled by allocating
duke@0
   // guard pages (red zone) and stackbanging.
duke@0
   // Initially the alternate signal stack mechanism was removed because
duke@0
   // it did not work with T1 llibthread. Alternate
duke@0
   // signal stacks MUST have all threads bound to lwps. Applications
duke@0
   // can create their own threads and attach them without their being
duke@0
   // bound under T1. This is frequently the case for the primordial thread.
duke@0
   // If we were ever to reenable this mechanism we would need to
duke@0
   // use the dynamic check for T2 libthread.
duke@0
duke@0
  os::Solaris::init_thread_fpu_state();
duke@0
}
duke@0
duke@0
duke@0
duke@0
// Free Solaris resources related to the OSThread
duke@0
void os::free_thread(OSThread* osthread) {
duke@0
  assert(osthread != NULL, "os::free_thread but osthread not set");
duke@0
duke@0
duke@0
  // We are told to free resources of the argument thread,
duke@0
  // but we can only really operate on the current thread.
duke@0
  // The main thread must take the VMThread down synchronously
duke@0
  // before the main thread exits and frees up CodeHeap
duke@0
  guarantee((Thread::current()->osthread() == osthread
duke@0
     || (osthread == VMThread::vm_thread()->osthread())), "os::free_thread but not current thread");
duke@0
  if (Thread::current()->osthread() == osthread) {
duke@0
    // Restore caller's signal mask
duke@0
    sigset_t sigmask = osthread->caller_sigmask();
duke@0
    thr_sigsetmask(SIG_SETMASK, &sigmask, NULL);
duke@0
  }
duke@0
  delete osthread;
duke@0
}
duke@0
duke@0
void os::pd_start_thread(Thread* thread) {
duke@0
  int status = thr_continue(thread->osthread()->thread_id());
duke@0
  assert_status(status == 0, status, "thr_continue failed");
duke@0
}
duke@0
duke@0
duke@0
intx os::current_thread_id() {
duke@0
  return (intx)thr_self();
duke@0
}
duke@0
duke@0
static pid_t _initial_pid = 0;
duke@0
duke@0
int os::current_process_id() {
duke@0
  return (int)(_initial_pid ? _initial_pid : getpid());
duke@0
}
duke@0
duke@0
int os::allocate_thread_local_storage() {
duke@0
  // %%%       in Win32 this allocates a memory segment pointed to by a
duke@0
  //           register.  Dan Stein can implement a similar feature in
duke@0
  //           Solaris.  Alternatively, the VM can do the same thing
duke@0
  //           explicitly: malloc some storage and keep the pointer in a
duke@0
  //           register (which is part of the thread's context) (or keep it
duke@0
  //           in TLS).
duke@0
  // %%%       In current versions of Solaris, thr_self and TSD can
duke@0
  //           be accessed via short sequences of displaced indirections.
duke@0
  //           The value of thr_self is available as %g7(36).
duke@0
  //           The value of thr_getspecific(k) is stored in %g7(12)(4)(k*4-4),
duke@0
  //           assuming that the current thread already has a value bound to k.
duke@0
  //           It may be worth experimenting with such access patterns,
duke@0
  //           and later having the parameters formally exported from a Solaris
duke@0
  //           interface.  I think, however, that it will be faster to
duke@0
  //           maintain the invariant that %g2 always contains the
duke@0
  //           JavaThread in Java code, and have stubs simply
duke@0
  //           treat %g2 as a caller-save register, preserving it in a %lN.
duke@0
  thread_key_t tk;
duke@0
  if (thr_keycreate( &tk, NULL ) )
jcoomes@1700
    fatal(err_msg("os::allocate_thread_local_storage: thr_keycreate failed "
jcoomes@1700
                  "(%s)", strerror(errno)));
duke@0
  return int(tk);
duke@0
}
duke@0
duke@0
void os::free_thread_local_storage(int index) {
duke@0
  // %%% don't think we need anything here
duke@0
  // if ( pthread_key_delete((pthread_key_t) tk) )
duke@0
  //   fatal("os::free_thread_local_storage: pthread_key_delete failed");
duke@0
}
duke@0
duke@0
#define SMALLINT 32   // libthread allocate for tsd_common is a version specific
duke@0
                      // small number - point is NO swap space available
duke@0
void os::thread_local_storage_at_put(int index, void* value) {
duke@0
  // %%% this is used only in threadLocalStorage.cpp
duke@0
  if (thr_setspecific((thread_key_t)index, value)) {
duke@0
    if (errno == ENOMEM) {
duke@0
       vm_exit_out_of_memory(SMALLINT, "thr_setspecific: out of swap space");
duke@0
    } else {
jcoomes@1700
      fatal(err_msg("os::thread_local_storage_at_put: thr_setspecific failed "
jcoomes@1700
                    "(%s)", strerror(errno)));
duke@0
    }
duke@0
  } else {
duke@0
      ThreadLocalStorage::set_thread_in_slot ((Thread *) value) ;
duke@0
  }
duke@0
}
duke@0
duke@0
// This function could be called before TLS is initialized, for example, when
duke@0
// VM receives an async signal or when VM causes a fatal error during
duke@0
// initialization. Return NULL if thr_getspecific() fails.
duke@0
void* os::thread_local_storage_at(int index) {
duke@0
  // %%% this is used only in threadLocalStorage.cpp
duke@0
  void* r = NULL;
duke@0
  return thr_getspecific((thread_key_t)index, &r) != 0 ? NULL : r;
duke@0
}
duke@0
duke@0
duke@0
const int NANOSECS_PER_MILLISECS = 1000000;
duke@0
// gethrtime can move backwards if read from one cpu and then a different cpu
duke@0
// getTimeNanos is guaranteed to not move backward on Solaris
duke@0
// local spinloop created as faster for a CAS on an int than
duke@0
// a CAS on a 64bit jlong. Also Atomic::cmpxchg for jlong is not
duke@0
// supported on sparc v8 or pre supports_cx8 intel boxes.
duke@0
// oldgetTimeNanos for systems which do not support CAS on 64bit jlong
duke@0
// i.e. sparc v8 and pre supports_cx8 (i486) intel boxes
duke@0
inline hrtime_t oldgetTimeNanos() {
duke@0
  int gotlock = LOCK_INVALID;
duke@0
  hrtime_t newtime = gethrtime();
duke@0
duke@0
  for (;;) {
duke@0
// grab lock for max_hrtime
duke@0
    int curlock = max_hrtime_lock;
duke@0
    if (curlock & LOCK_BUSY)  continue;
duke@0
    if (gotlock = Atomic::cmpxchg(LOCK_BUSY, &max_hrtime_lock, LOCK_FREE) != LOCK_FREE) continue;
duke@0
    if (newtime > max_hrtime) {
duke@0
      max_hrtime = newtime;
duke@0
    } else {
duke@0
      newtime = max_hrtime;
duke@0
    }
duke@0
    // release lock
duke@0
    max_hrtime_lock = LOCK_FREE;
duke@0
    return newtime;
duke@0
  }
duke@0
}
duke@0
// gethrtime can move backwards if read from one cpu and then a different cpu
duke@0
// getTimeNanos is guaranteed to not move backward on Solaris
duke@0
inline hrtime_t getTimeNanos() {
duke@0
  if (VM_Version::supports_cx8()) {
xlu@557
    const hrtime_t now = gethrtime();
kvn@1017
    // Use atomic long load since 32-bit x86 uses 2 registers to keep long.
kvn@1017
    const hrtime_t prev = Atomic::load((volatile jlong*)&max_hrtime);
xlu@557
    if (now <= prev)  return prev;   // same or retrograde time;
xlu@557
    const hrtime_t obsv = Atomic::cmpxchg(now, (volatile jlong*)&max_hrtime, prev);
xlu@557
    assert(obsv >= prev, "invariant");   // Monotonicity
xlu@557
    // If the CAS succeeded then we're done and return "now".
xlu@557
    // If the CAS failed and the observed value "obs" is >= now then
xlu@557
    // we should return "obs".  If the CAS failed and now > obs > prv then
xlu@557
    // some other thread raced this thread and installed a new value, in which case
xlu@557
    // we could either (a) retry the entire operation, (b) retry trying to install now
xlu@557
    // or (c) just return obs.  We use (c).   No loop is required although in some cases
xlu@557
    // we might discard a higher "now" value in deference to a slightly lower but freshly
xlu@557
    // installed obs value.   That's entirely benign -- it admits no new orderings compared
xlu@557
    // to (a) or (b) -- and greatly reduces coherence traffic.
xlu@557
    // We might also condition (c) on the magnitude of the delta between obs and now.
xlu@557
    // Avoiding excessive CAS operations to hot RW locations is critical.
xlu@557
    // See http://blogs.sun.com/dave/entry/cas_and_cache_trivia_invalidate
xlu@557
    return (prev == obsv) ? now : obsv ;
duke@0
  } else {
duke@0
    return oldgetTimeNanos();
duke@0
  }
duke@0
}
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
  return (double)(getTimeNanos() - first_hrtime) / (double)hrtime_hz;
duke@0
}
duke@0
duke@0
jlong os::elapsed_counter() {
duke@0
  return (jlong)(getTimeNanos() - first_hrtime);
duke@0
}
duke@0
duke@0
jlong os::elapsed_frequency() {
duke@0
   return hrtime_hz;
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
    // For consistency return the real time from getTimeNanos()
duke@0
    // converted to seconds.
duke@0
    *process_real_time = ((double) getTimeNanos()) / ((double) NANOUNITS);
duke@0
duke@0
    return true;
duke@0
  }
duke@0
}
duke@0
ysr@397
bool os::supports_vtime() { return true; }
ysr@397
ysr@397
bool os::enable_vtime() {
ysr@397
  int fd = open("/proc/self/ctl", O_WRONLY);
ysr@397
  if (fd == -1)
ysr@397
    return false;
ysr@397
ysr@397
  long cmd[] = { PCSET, PR_MSACCT };
ysr@397
  int res = write(fd, cmd, sizeof(long) * 2);
ysr@397
  close(fd);
ysr@397
  if (res != sizeof(long) * 2)
ysr@397
    return false;
ysr@397
ysr@397
  return true;
ysr@397
}
ysr@397
ysr@397
bool os::vtime_enabled() {
ysr@397
  int fd = open("/proc/self/status", O_RDONLY);
ysr@397
  if (fd == -1)
ysr@397
    return false;
ysr@397
ysr@397
  pstatus_t status;
ysr@397
  int res = read(fd, (void*) &status, sizeof(pstatus_t));
ysr@397
  close(fd);
ysr@397
  if (res != sizeof(pstatus_t))
ysr@397
    return false;
ysr@397
ysr@397
  return status.pr_flags & PR_MSACCT;
ysr@397
}
ysr@397
ysr@397
double os::elapsedVTime() {
ysr@397
  return (double)gethrvtime() / (double)hrtime_hz;
ysr@397
}
ysr@397
duke@0
// Used internally for comparisons only
duke@0
// getTimeMillis guaranteed to not move backwards on Solaris
duke@0
jlong getTimeMillis() {
duke@0
  jlong nanotime = getTimeNanos();
duke@0
  return (jlong)(nanotime / NANOSECS_PER_MILLISECS);
duke@0
}
duke@0
sbohne@119
// Must return millis since Jan 1 1970 for JVM_CurrentTimeMillis
sbohne@119
jlong os::javaTimeMillis() {
duke@0
  timeval t;
duke@0
  if (gettimeofday( &t, NULL) == -1)
jcoomes@1700
    fatal(err_msg("os::javaTimeMillis: gettimeofday (%s)", strerror(errno)));
duke@0
  return jlong(t.tv_sec) * 1000  +  jlong(t.tv_usec) / 1000;
duke@0
}
duke@0
duke@0
jlong os::javaTimeNanos() {
duke@0
  return (jlong)getTimeNanos();
duke@0
}
duke@0
duke@0
void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) {
duke@0
  info_ptr->max_value = ALL_64_BITS;      // gethrtime() uses all 64 bits
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
  info_ptr->kind = JVMTI_TIMER_ELAPSED;   // elapsed not CPU time
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;
duke@0
}
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
// 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 (for debugging)
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(-1);
duke@0
}
duke@0
duke@0
// unused
duke@0
void os::set_error_file(const char *logfile) {}
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) {
bobv@1892
    *buffer = '\0';
bobv@1892
    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 what the heck, 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
typedef int (*dladdr1_func_type) (void *, Dl_info *, void **, int);
duke@0
static dladdr1_func_type dladdr1_func = NULL;
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
  // dladdr1_func was initialized in os::init()
duke@0
  if (dladdr1_func){
duke@0
      // yes, we have dladdr1
duke@0
duke@0
      // Support for dladdr1 is checked at runtime; it may be
duke@0
      // available even if the vm is built on a machine that does
duke@0
      // not have dladdr1 support.  Make sure there is a value for
duke@0
      // RTLD_DL_SYMENT.
duke@0
      #ifndef RTLD_DL_SYMENT
duke@0
      #define RTLD_DL_SYMENT 1
duke@0
      #endif
duke@0
      Sym * info;
duke@0
      if (dladdr1_func((void *)addr, &dlinfo, (void **)&info,
duke@0
                       RTLD_DL_SYMENT)) {
duke@0
          if (buf) jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname);
duke@0
          if (offset) *offset = addr - (address)dlinfo.dli_saddr;
duke@0
duke@0
          // check if the returned symbol really covers addr
duke@0
          return ((char *)dlinfo.dli_saddr + info->st_size > (char *)addr);
duke@0
      } else {
duke@0
          if (buf) buf[0] = '\0';
duke@0
          if (offset) *offset  = -1;
duke@0
          return false;
duke@0
      }
duke@0
  } else {
duke@0
      // no, only dladdr is available
duke@0
      if(dladdr((void *)addr, &dlinfo)) {
duke@0
          if (buf) jio_snprintf(buf, buflen, 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
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
duke@0
  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
// Prints the names and full paths of all opened dynamic libraries
duke@0
// for current process
duke@0
void os::print_dll_info(outputStream * st) {
duke@0
    Dl_info dli;
duke@0
    void *handle;
duke@0
    Link_map *map;
duke@0
    Link_map *p;
duke@0
duke@0
    st->print_cr("Dynamic libraries:"); st->flush();
duke@0
duke@0
    if (!dladdr(CAST_FROM_FN_PTR(void *, os::print_dll_info), &dli)) {
duke@0
        st->print_cr("Error: Cannot print dynamic libraries.");
duke@0
        return;
duke@0
    }
duke@0
    handle = dlopen(dli.dli_fname, RTLD_LAZY);
duke@0
    if (handle == NULL) {
duke@0
        st->print_cr("Error: Cannot print dynamic libraries.");
duke@0
        return;
duke@0
    }
duke@0
    dlinfo(handle, RTLD_DI_LINKMAP, &map);
duke@0
    if (map == NULL) {
duke@0
        st->print_cr("Error: Cannot print dynamic libraries.");
duke@0
        return;
duke@0
    }
duke@0
duke@0
    while (map->l_prev != NULL)
duke@0
        map = map->l_prev;
duke@0
duke@0
    while (map != NULL) {
duke@0
        st->print_cr(PTR_FORMAT " \t%s", map->l_addr, map->l_name);
duke@0
        map = map->l_next;
duke@0
    }
duke@0
duke@0
    dlclose(handle);
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
  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"},
bobv@1892
    {EM_PPC64,       EM_PPC64,   ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"},
bobv@1892
    {EM_ARM,         EM_ARM,     ELFCLASS32, ELFDATA2LSB, (char*)"ARM 32"}
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;
bobv@1892
  #elif (defined ARM)
bobv@1892
    static  Elf32_Half running_arch_code=EM_ARM;
duke@0
  #else
duke@0
    #error Method os::dll_load requires that one of following is defined:\
bobv@1892
         IA32, AMD64, IA64, __sparc, __powerpc__, ARM, ARM
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
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
  }
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
void* os::dll_lookup(void* handle, const char* name) {
kamg@299
  return dlsym(handle, name);
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_os_info(outputStream* st) {
duke@0
  st->print("OS:");
duke@0
duke@0
  if (!_print_ascii_file("/etc/release", st)) {
duke@0
    st->print("Solaris");
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
duke@0
  // libthread
duke@0
  if (os::Solaris::T2_libthread()) st->print("  (T2 libthread)");
duke@0
  else st->print("  (T1 libthread)");
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(", 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]);
duke@0
  st->cr();
duke@0
}
duke@0
duke@0
duke@0
static bool check_addr0(outputStream* st) {
duke@0
  jboolean status = false;
duke@0
  int fd = open("/proc/self/map",O_RDONLY);
duke@0
  if (fd >= 0) {
duke@0
    prmap_t p;
duke@0
    while(read(fd, &p, sizeof(p)) > 0) {
duke@0
      if (p.pr_vaddr == 0x0) {
duke@0
        st->print("Warning: Address: 0x%x, Size: %dK, ",p.pr_vaddr, p.pr_size/1024, p.pr_mapname);
duke@0
        st->print("Mapped file: %s, ", p.pr_mapname[0] == '\0' ? "None" : p.pr_mapname);
duke@0
        st->print("Access:");
duke@0
        st->print("%s",(p.pr_mflags & MA_READ)  ? "r" : "-");
duke@0
        st->print("%s",(p.pr_mflags & MA_WRITE) ? "w" : "-");
duke@0
        st->print("%s",(p.pr_mflags & MA_EXEC)  ? "x" : "-");
duke@0
        st->cr();
duke@0
        status = true;
duke@0
      }
duke@0
      close(fd);
duke@0
    }
duke@0
  }
duke@0
  return status;
duke@0
}
duke@0
duke@0
void os::print_memory_info(outputStream* st) {
duke@0
  st->print("Memory:");
duke@0
  st->print(" %dk page", os::vm_page_size()>>10);
duke@0
  st->print(", physical " UINT64_FORMAT "k", os::physical_memory()>>10);
duke@0
  st->print("(" UINT64_FORMAT "k free)", os::available_memory() >> 10);
duke@0
  st->cr();
duke@0
  (void) check_addr0(st);
duke@0
}
duke@0
duke@0
// Taken from /usr/include/sys/machsig.h  Supposed to be architecture specific
duke@0
// but they're the same for all the solaris architectures that we support.
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" };
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
  char *err = strerror(si->si_errno);
duke@0
  if (si->si_errno != 0 && err != NULL) {
duke@0
    st->print("si_errno=%s", err);
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
// Moved from whole group, because we need them here for diagnostic
duke@0
// prints.
duke@0
#define OLDMAXSIGNUM 32
duke@0
static int Maxsignum = 0;
duke@0
static int *ourSigFlags = NULL;
duke@0
duke@0
extern "C" void sigINTRHandler(int, siginfo_t*, void*);
duke@0
duke@0
int os::Solaris::get_our_sigflags(int sig) {
duke@0
  assert(ourSigFlags!=NULL, "signal data structure not initialized");
duke@0
  assert(sig > 0 && sig < Maxsignum, "vm signal out of expected range");
duke@0
  return ourSigFlags[sig];
duke@0
}
duke@0
duke@0
void os::Solaris::set_our_sigflags(int sig, int flags) {
duke@0
  assert(ourSigFlags!=NULL, "signal data structure not initialized");
duke@0
  assert(sig > 0 && sig < Maxsignum, "vm signal out of expected range");
duke@0
  ourSigFlags[sig] = flags;
duke@0
}
duke@0
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
  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);
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, signalHandler) ||
duke@0
     handler == CAST_FROM_FN_PTR(address, sigINTRHandler)) {
duke@0
    // It is our signal handler
duke@0
    // check for flags
duke@0
    if(sa.sa_flags != os::Solaris::get_our_sigflags(sig)) {
duke@0
      st->print(
duke@0
        ", flags was changed from " PTR32_FORMAT ", consider using jsig library",
duke@0
        os::Solaris::get_our_sigflags(sig));
duke@0
    }
duke@0
  }
duke@0
  st->cr();
duke@0
}
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, ASYNC_SIGNAL, buf, buflen);
duke@0
  print_signal_handler(st, BREAK_SIGNAL, 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, os::Solaris::SIGinterrupt(), buf, buflen);
duke@0
  print_signal_handler(st, os::Solaris::SIGasync(), 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
duke@0
void os::jvm_path(char *buf, jint buflen) {
duke@0
  // Error checking.
duke@0
  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
  Dl_info dlinfo;
duke@0
  int ret = dladdr(CAST_FROM_FN_PTR(void *, os::jvm_path), &dlinfo);
duke@0
  assert(ret != 0, "cannot locate libjvm");
duke@0
  realpath((char *)dlinfo.dli_fname, buf);
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) {
duke@0
        char cpu_arch[12];
mchung@1839
        char* jrelib_p;
mchung@1839
        int   len;
duke@0
        sysinfo(SI_ARCHITECTURE, cpu_arch, sizeof(cpu_arch));
duke@0
#ifdef _LP64
duke@0
        // If we are on sparc running a 64-bit vm, look in jre/lib/sparcv9.
duke@0
        if (strcmp(cpu_arch, "sparc") == 0) {
duke@0
          strcat(cpu_arch, "v9");
duke@0
        } else if (strcmp(cpu_arch, "i386") == 0) {
duke@0
          strcpy(cpu_arch, "amd64");
duke@0
        }
duke@0
#endif
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
duke@0
        realpath(java_home_var, buf);
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
duke@0
          realpath((char *)dlinfo.dli_fname, buf);
duke@0
        }
duke@0
      }
duke@0
    }
duke@0
  }
duke@0
duke@0
  strcpy(saved_jvm_path, buf);
duke@0
}
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
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
duke@0
duke@0
extern "C" {
duke@0
  static void UserHandler(int sig, void *siginfo, void *context) {
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
    // We do not need to reinstate the signal handler each time...
duke@0
  }
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
  sigfillset(&(sigAct.sa_mask));
duke@0
  sigAct.sa_flags = SA_RESTART & ~SA_RESETHAND;
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
  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
// a counter for each possible signal value
duke@0
static int Sigexit = 0;
duke@0
static int Maxlibjsigsigs;
duke@0
static jint *pending_signals = NULL;
duke@0
static int *preinstalled_sigs = NULL;
duke@0
static struct sigaction *chainedsigactions = NULL;
duke@0
static sema_t sig_sem;
duke@0
typedef int (*version_getting_t)();
duke@0
version_getting_t os::Solaris::get_libjsig_version = NULL;
duke@0
static int libjsigversion = NULL;
duke@0
duke@0
int os::sigexitnum_pd() {
duke@0
  assert(Sigexit > 0, "signal memory not yet initialized");
duke@0
  return Sigexit;
duke@0
}
duke@0
duke@0
void os::Solaris::init_signal_mem() {
duke@0
  // Initialize signal structures
duke@0
  Maxsignum = SIGRTMAX;
duke@0
  Sigexit = Maxsignum+1;
duke@0
  assert(Maxsignum >0, "Unable to obtain max signal number");
duke@0
duke@0
  Maxlibjsigsigs = Maxsignum;
duke@0
duke@0
  // pending_signals has one int per signal
duke@0
  // The additional signal is for SIGEXIT - exit signal to signal_thread
duke@0
  pending_signals = (jint *)os::malloc(sizeof(jint) * (Sigexit+1));
duke@0
  memset(pending_signals, 0, (sizeof(jint) * (Sigexit+1)));
duke@0
duke@0
  if (UseSignalChaining) {
duke@0
     chainedsigactions = (struct sigaction *)malloc(sizeof(struct sigaction)
duke@0
       * (Maxsignum + 1));
duke@0
     memset(chainedsigactions, 0, (sizeof(struct sigaction) * (Maxsignum + 1)));
duke@0
     preinstalled_sigs = (int *)os::malloc(sizeof(int) * (Maxsignum + 1));
duke@0
     memset(preinstalled_sigs, 0, (sizeof(int) * (Maxsignum + 1)));
duke@0
  }
duke@0
  ourSigFlags = (int*)malloc(sizeof(int) * (Maxsignum + 1 ));
duke@0
  memset(ourSigFlags, 0, sizeof(int) * (Maxsignum + 1));
duke@0
}
duke@0
duke@0
void os::signal_init_pd() {
duke@0
  int ret;
duke@0
duke@0
  ret = ::sema_init(&sig_sem, 0, NULL, NULL);
duke@0
  assert(ret == 0, "sema_init() failed");
duke@0
}
duke@0
duke@0
void os::signal_notify(int signal_number) {
duke@0
  int ret;
duke@0
duke@0
  Atomic::inc(&pending_signals[signal_number]);
duke@0
  ret = ::sema_post(&sig_sem);
duke@0
  assert(ret == 0, "sema_post() failed");
duke@0
}
duke@0
duke@0
static int check_pending_signals(bool wait_for_signal) {
duke@0
  int ret;
duke@0
  while (true) {
duke@0
    for (int i = 0; i < Sigexit + 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_for_signal) {
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
      while((ret = ::sema_wait(&sig_sem)) == EINTR)
duke@0
          ;
duke@0
      assert(ret == 0, "sema_wait() failed");
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
        ret = ::sema_post(&sig_sem);
duke@0
        assert(ret == 0, "sema_post() failed");
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
static int page_size = -1;
duke@0
duke@0
// The mmap MAP_ALIGN flag is supported on Solaris 9 and later.  init_2() will
duke@0
// clear this var if support is not available.
duke@0
static bool has_map_align = true;
duke@0
duke@0
int os::vm_page_size() {
duke@0
  assert(page_size != -1, "must call os::init");
duke@0
  return page_size;
duke@0
}
duke@0
duke@0
// Solaris allocates memory by pages.
duke@0
int os::vm_allocation_granularity() {
duke@0
  assert(page_size != -1, "must call os::init");
duke@0
  return page_size;
duke@0
}
duke@0
coleenp@783
bool os::commit_memory(char* addr, size_t bytes, bool exec) {
coleenp@783
  int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
duke@0
  size_t size = bytes;
duke@0
  return
coleenp@783
     NULL != Solaris::mmap_chunk(addr, size, MAP_PRIVATE|MAP_FIXED, prot);
coleenp@783
}
coleenp@783
coleenp@783
bool os::commit_memory(char* addr, size_t bytes, size_t alignment_hint,
coleenp@783
                       bool exec) {
coleenp@783
  if (commit_memory(addr, bytes, exec)) {
duke@0
    if (UseMPSS && alignment_hint > (size_t)vm_page_size()) {
duke@0
      // If the large page size has been set and the VM
duke@0
      // is using large pages, use the large page size
duke@0
      // if it is smaller than the alignment hint. This is
duke@0
      // a case where the VM wants to use a larger alignment size
duke@0
      // for its own reasons but still want to use large pages
duke@0
      // (which is what matters to setting the mpss range.
duke@0
      size_t page_size = 0;
duke@0
      if (large_page_size() < alignment_hint) {
duke@0
        assert(UseLargePages, "Expected to be here for large page use only");
duke@0
        page_size = large_page_size();
duke@0
      } else {
duke@0
        // If the alignment hint is less than the large page
duke@0
        // size, the VM wants a particular alignment (thus the hint)
duke@0
        // for internal reasons.  Try to set the mpss range using
duke@0
        // the alignment_hint.
duke@0
        page_size = alignment_hint;
duke@0
      }
duke@0
      // Since this is a hint, ignore any failures.
duke@0
      (void)Solaris::set_mpss_range(addr, bytes, page_size);
duke@0
    }
duke@0
    return true;
duke@0
  }
duke@0
  return false;
duke@0
}
duke@0
duke@0
// Uncommit the pages in a specified region.
duke@0
void os::free_memory(char* addr, size_t bytes) {
duke@0
  if (madvise(addr, bytes, MADV_FREE) < 0) {
duke@0
    debug_only(warning("MADV_FREE failed."));
duke@0
    return;
duke@0
  }
coleenp@1621
}
coleenp@1621
coleenp@1621
bool os::create_stack_guard_pages(char* addr, size_t size) {
coleenp@1621
  return os::commit_memory(addr, size);
coleenp@1621
}
coleenp@1621
coleenp@1621
bool os::remove_stack_guard_pages(char* addr, size_t size) {
coleenp@1621
  return os::uncommit_memory(addr, size);
duke@0
}
duke@0
duke@0
// Change the page size in a given range.
duke@0
void os::realign_memory(char *addr, size_t bytes, size_t alignment_hint) {
duke@0
  assert((intptr_t)addr % alignment_hint == 0, "Address should be aligned.");
duke@0
  assert((intptr_t)(addr + bytes) % alignment_hint == 0, "End should be aligned.");
duke@0
  Solaris::set_mpss_range(addr, bytes, alignment_hint);
duke@0
}
duke@0
duke@0
// Tell the OS to make the range local to the first-touching LWP
iveresov@198
void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) {
duke@0
  assert((intptr_t)addr % os::vm_page_size() == 0, "Address should be page-aligned.");
duke@0
  if (madvise(addr, bytes, MADV_ACCESS_LWP) < 0) {
duke@0
    debug_only(warning("MADV_ACCESS_LWP failed."));
duke@0
  }
duke@0
}
duke@0
duke@0
// Tell the OS that this range would be accessed from different LWPs.
duke@0
void os::numa_make_global(char *addr, size_t bytes) {
duke@0
  assert((intptr_t)addr % os::vm_page_size() == 0, "Address should be page-aligned.");
duke@0
  if (madvise(addr, bytes, MADV_ACCESS_MANY) < 0) {
duke@0
    debug_only(warning("MADV_ACCESS_MANY failed."));
duke@0
  }
duke@0
}
duke@0
duke@0
// Get the number of the locality groups.
duke@0
size_t os::numa_get_groups_num() {
duke@0
  size_t n = Solaris::lgrp_nlgrps(Solaris::lgrp_cookie());
duke@0
  return n != -1 ? n : 1;
duke@0
}
duke@0
duke@0
// Get a list of leaf locality groups. A leaf lgroup is group that
duke@0
// doesn't have any children. Typical leaf group is a CPU or a CPU/memory
duke@0
// board. An LWP is assigned to one of these groups upon creation.
duke@0
size_t os::numa_get_leaf_groups(int *ids, size_t size) {
duke@0
   if ((ids[0] = Solaris::lgrp_root(Solaris::lgrp_cookie())) == -1) {
duke@0
     ids[0] = 0;
duke@0
     return 1;
duke@0
   }
duke@0
   int result_size = 0, top = 1, bottom = 0, cur = 0;
duke@0
   for (int k = 0; k < size; k++) {
duke@0
     int r = Solaris::lgrp_children(Solaris::lgrp_cookie(), ids[cur],
duke@0
                                    (Solaris::lgrp_id_t*)&ids[top], size - top);
duke@0
     if (r == -1) {
duke@0
       ids[0] = 0;
duke@0
       return 1;
duke@0
     }
duke@0
     if (!r) {
iveresov@201
       // That's a leaf node.
duke@0
       assert (bottom <= cur, "Sanity check");
iveresov@201
       // Check if the node has memory
iveresov@201
       if (Solaris::lgrp_resources(Solaris::lgrp_cookie(), ids[cur],
iveresov@201
                                   NULL, 0, LGRP_RSRC_MEM) > 0) {
iveresov@201
         ids[bottom++] = ids[cur];
iveresov@201
       }
duke@0
     }
duke@0
     top += r;
duke@0
     cur++;
iveresov@325
   }
iveresov@325
   if (bottom == 0) {
iveresov@325
     // Handle a situation, when the OS reports no memory available.
iveresov@325
     // Assume UMA architecture.
iveresov@325
     ids[0] = 0;
iveresov@325
     return 1;
duke@0
   }
duke@0
   return bottom;
duke@0
}
duke@0
ysr@397
// Detect the topology change. Typically happens during CPU plugging-unplugging.
duke@0
bool os::numa_topology_changed() {
duke@0
  int is_stale = Solaris::lgrp_cookie_stale(Solaris::lgrp_cookie());
duke@0
  if (is_stale != -1 && is_stale) {
duke@0
    Solaris::lgrp_fini(Solaris::lgrp_cookie());
duke@0
    Solaris::lgrp_cookie_t c = Solaris::lgrp_init(Solaris::LGRP_VIEW_CALLER);
duke@0
    assert(c != 0, "Failure to initialize LGRP API");
duke@0
    Solaris::set_lgrp_cookie(c);
duke@0
    return true;
duke@0
  }
duke@0
  return false;
duke@0
}
duke@0
duke@0
// Get the group id of the current LWP.
duke@0
int os::numa_get_group_id() {
iveresov@201
  int lgrp_id = Solaris::lgrp_home(P_LWPID, P_MYID);
duke@0
  if (lgrp_id == -1) {
duke@0
    return 0;
duke@0
  }
iveresov@201
  const int size = os::numa_get_groups_num();
iveresov@201
  int *ids = (int*)alloca(size * sizeof(int));
iveresov@201
iveresov@201
  // Get the ids of all lgroups with memory; r is the count.
iveresov@201
  int r = Solaris::lgrp_resources(Solaris::lgrp_cookie(), lgrp_id,
iveresov@201
                                  (Solaris::lgrp_id_t*)ids, size, LGRP_RSRC_MEM);
iveresov@201
  if (r <= 0) {
iveresov@201
    return 0;
iveresov@201
  }
iveresov@201
  return ids[os::random() % r];
duke@0
}
duke@0
duke@0
// Request information about the page.
duke@0
bool os::get_page_info(char *start, page_info* info) {
duke@0
  const uint_t info_types[] = { MEMINFO_VLGRP, MEMINFO_VPAGESIZE };
duke@0
  uint64_t addr = (uintptr_t)start;
duke@0
  uint64_t outdata[2];
duke@0
  uint_t validity = 0;
duke@0
duke@0
  if (os::Solaris::meminfo(&addr, 1, info_types, 2, outdata, &validity) < 0) {
duke@0
    return false;
duke@0
  }
duke@0
duke@0
  info->size = 0;
duke@0
  info->lgrp_id = -1;
duke@0
duke@0
  if ((validity & 1) != 0) {
duke@0
    if ((validity & 2) != 0) {
duke@0
      info->lgrp_id = outdata[0];
duke@0
    }
duke@0
    if ((validity & 4) != 0) {
duke@0
      info->size = outdata[1];
duke@0
    }
duke@0
    return true;
duke@0
  }
duke@0
  return false;
duke@0
}
duke@0
duke@0
// Scan the pages from start to end until a page different than
duke@0
// the one described in the info parameter is encountered.
duke@0
char *os::scan_pages(char *start, char* end, page_info* page_expected, page_info* page_found) {
duke@0
  const uint_t info_types[] = { MEMINFO_VLGRP, MEMINFO_VPAGESIZE };
duke@0
  const size_t types = sizeof(info_types) / sizeof(info_types[0]);
duke@0
  uint64_t addrs[MAX_MEMINFO_CNT], outdata[types * MAX_MEMINFO_CNT];
duke@0
  uint_t validity[MAX_MEMINFO_CNT];
duke@0
duke@0
  size_t page_size = MAX2((size_t)os::vm_page_size(), page_expected->size);
duke@0
  uint64_t p = (uint64_t)start;
duke@0
  while (p < (uint64_t)end) {
duke@0
    addrs[0] = p;
duke@0
    size_t addrs_count = 1;
duke@0
    while (addrs_count < MAX_MEMINFO_CNT && addrs[addrs_count - 1] < (uint64_t)end) {
duke@0
      addrs[addrs_count] = addrs[addrs_count - 1] + page_size;
duke@0
      addrs_count++;
duke@0
    }
duke@0
duke@0
    if (os::Solaris::meminfo(addrs, addrs_count, info_types, types, outdata, validity) < 0) {
duke@0
      return NULL;
duke@0
    }
duke@0
duke@0
    size_t i = 0;
duke@0
    for (; i < addrs_count; i++) {
duke@0
      if ((validity[i] & 1) != 0) {
duke@0
        if ((validity[i] & 4) != 0) {
duke@0
          if (outdata[types * i + 1] != page_expected->size) {
duke@0
            break;
duke@0
          }
duke@0
        } else
duke@0
          if (page_expected->size != 0) {
duke@0
            break;
duke@0
          }
duke@0
duke@0
        if ((validity[i] & 2) != 0 && page_expected->lgrp_id > 0) {
duke@0
          if (outdata[types * i] != page_expected->lgrp_id) {
duke@0
            break;
duke@0
          }
duke@0
        }
duke@0
      } else {
duke@0
        return NULL;
duke@0
      }
duke@0
    }
duke@0
duke@0
    if (i != addrs_count) {
duke@0
      if ((validity[i] & 2) != 0) {
duke@0
        page_found->lgrp_id = outdata[types * i];
duke@0
      } else {
duke@0
        page_found->lgrp_id = -1;
duke@0
      }
duke@0
      if ((validity[i] & 4) != 0) {
duke@0
        page_found->size = outdata[types * i + 1];
duke@0
      } else {
duke@0
        page_found->size = 0;
duke@0
      }
duke@0
      return (char*)addrs[i];
duke@0
    }
duke@0
duke@0
    p = addrs[addrs_count - 1] + page_size;
duke@0
  }
duke@0
  return end;
duke@0
}
duke@0
duke@0
bool os::uncommit_memory(char* addr, size_t bytes) {
duke@0
  size_t size = bytes;
duke@0
  // Map uncommitted pages PROT_NONE so we fail early if we touch an
duke@0
  // uncommitted page. Otherwise, the read/write might succeed if we
duke@0
  // have enough swap space to back the physical page.
duke@0
  return
duke@0
    NULL != Solaris::mmap_chunk(addr, size,
duke@0
                                MAP_PRIVATE|MAP_FIXED|MAP_NORESERVE,
duke@0
                                PROT_NONE);
duke@0
}
duke@0
duke@0
char* os::Solaris::mmap_chunk(char *addr, size_t size, int flags, int prot) {
duke@0
  char *b = (char *)mmap(addr, size, prot, flags, os::Solaris::_dev_zero_fd, 0);
duke@0
duke@0
  if (b == MAP_FAILED) {
duke@0
    return NULL;
duke@0
  }
duke@0
  return b;
duke@0
}
duke@0
sbohne@118
char* os::Solaris::anon_mmap(char* requested_addr, size_t bytes, size_t alignment_hint, bool fixed) {
sbohne@118
  char* addr = requested_addr;
sbohne@118
  int flags = MAP_PRIVATE | MAP_NORESERVE;
sbohne@118
sbohne@118
  assert(!(fixed && (alignment_hint > 0)), "alignment hint meaningless with fixed mmap");
sbohne@118
sbohne@118
  if (fixed) {
sbohne@118
    flags |= MAP_FIXED;
sbohne@118
  } else if (has_map_align && (alignment_hint > (size_t) vm_page_size())) {
duke@0
    flags |= MAP_ALIGN;
duke@0
    addr = (char*) alignment_hint;
duke@0
  }
duke@0
duke@0
  // Map uncommitted pages PROT_NONE so we fail early if we touch an
duke@0
  // uncommitted page. Otherwise, the read/write might succeed if we
duke@0
  // have enough swap space to back the physical page.
sbohne@118
  return mmap_chunk(addr, bytes, flags, PROT_NONE);
sbohne@118
}
sbohne@118
sbohne@118
char* os::reserve_memory(size_t bytes, char* requested_addr, size_t alignment_hint) {
sbohne@118
  char* addr = Solaris::anon_mmap(requested_addr, bytes, alignment_hint, (requested_addr != NULL));
duke@0
duke@0
  guarantee(requested_addr == NULL || requested_addr == addr,
duke@0
            "OS failed to return requested mmap address.");
duke@0
  return addr;
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
duke@0
  // Solaris adds a gap between mmap'ed regions.  The size of the gap
duke@0
  // is dependent on the requested size and the MMU.  Our initial gap
duke@0
  // value here is just a guess and will be corrected later.
duke@0
  bool had_top_overlap = false;
duke@0
  bool have_adjusted_gap = false;
duke@0
  size_t gap = 0x400000;
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
sbohne@118
  // Since snv_84, Solaris attempts to honor the address hint - see 5003415.
sbohne@118
  // Give it a try, if the kernel honors the hint we can return immediately.
sbohne@118
  char* addr = Solaris::anon_mmap(requested_addr, bytes, 0, false);
sbohne@118
  volatile int err = errno;
sbohne@118
  if (addr == requested_addr) {
sbohne@118
    return addr;
sbohne@118
  } else if (addr != NULL) {
sbohne@118
    unmap_memory(addr, bytes);
sbohne@118
  }
sbohne@118
sbohne@118
  if (PrintMiscellaneous && Verbose) {
sbohne@118
    char buf[256];
sbohne@118
    buf[0] = '\0';
sbohne@118
    if (addr == NULL) {
sbohne@118
      jio_snprintf(buf, sizeof(buf), ": %s", strerror(err));
sbohne@118
    }
sbohne@118
    warning("attempt_reserve_memory_at: couldn't reserve %d bytes at "
sbohne@118
            PTR_FORMAT ": reserve_memory_helper returned " PTR_FORMAT
sbohne@118
            "%s", bytes, requested_addr, addr, buf);
sbohne@118
  }
sbohne@118
sbohne@118
  // Address hint method didn't work.  Fall back to the old method.
sbohne@118
  // In theory, once SNV becomes our oldest supported platform, this
sbohne@118
  // code will no longer be needed.
sbohne@118
  //
duke@0
  // Repeatedly allocate blocks until the block is allocated at the
duke@0
  // right spot. Give up after max_tries.
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
      // check that the gap value is right
duke@0
      if (had_top_overlap && !have_adjusted_gap) {
duke@0
        size_t actual_gap = base[i-1] - base[i] - bytes;
duke@0
        if (gap != actual_gap) {
duke@0
          // adjust the gap value and retry the last 2 allocations
duke@0
          assert(i > 0, "gap adjustment code problem");
duke@0
          have_adjusted_gap = true;  // adjust the gap only once, just in case
duke@0
          gap = actual_gap;
duke@0
          if (PrintMiscellaneous && Verbose) {
duke@0
            warning("attempt_reserve_memory_at: adjusted gap to 0x%lx", gap);
duke@0
          }
duke@0
          unmap_memory(base[i], bytes);
duke@0
          unmap_memory(base[i-1], size[i-1]);
duke@0
          i-=2;
duke@0
          continue;
duke@0
        }
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
      // There is still a bug in this code: if top_overlap == bytes,
duke@0
      // the overlap is offset from requested region by the value of gap.
duke@0
      // In this case giving back the overlapped part will not work,
duke@0
      // because we'll give back the entire block at base[i] and
duke@0
      // therefore the subsequent allocation will not generate a new gap.
duke@0
      // This could be fixed with a new algorithm that used larger
duke@0
      // or variable size chunks to find the requested region -
duke@0
      // but such a change would introduce additional complications.
duke@0
      // It's rare enough that the planets align for this bug,
duke@0
      // so we'll just wait for a fix for 6204603/5003415 which
duke@0
      // will provide a mmap flag to allow us to avoid this business.
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
        had_top_overlap = true;
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
          if (PrintMiscellaneous && Verbose && bottom_overlap == 0) {
duke@0
            warning("attempt_reserve_memory_at: possible alignment bug");
duke@0
          }
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
  return (i < max_tries) ? requested_addr : NULL;
duke@0
}
duke@0
duke@0
bool os::release_memory(char* addr, size_t bytes) {
duke@0
  size_t size = bytes;
duke@0
  return munmap(addr, size) == 0;
duke@0
}
duke@0
duke@0
static bool solaris_mprotect(char* addr, size_t bytes, int prot) {
duke@0
  assert(addr == (char*)align_size_down((uintptr_t)addr, os::vm_page_size()),
duke@0
         "addr must be page aligned");
duke@0
  int retVal = mprotect(addr, bytes, prot);
duke@0
  return retVal == 0;
duke@0
}
duke@0
coleenp@295
// Protect memory (Used to pass readonly pages through
duke@0
// JNI GetArray<type>Elements with empty arrays.)
coleenp@533
// Also, used for serialization page and for compressed oops null pointer
coleenp@533
// checking.
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 solaris_mprotect(addr, bytes, p);
duke@0
}
duke@0
duke@0
// guard_memory and unguard_memory only happens within stack guard pages.
duke@0
// Since ISM pertains only to the heap, guard and unguard memory should not
duke@0
/// happen with an ISM region.
duke@0
bool os::guard_memory(char* addr, size_t bytes) {
duke@0
  return solaris_mprotect(addr, bytes, PROT_NONE);
duke@0
}
duke@0
duke@0
bool os::unguard_memory(char* addr, size_t bytes) {
coleenp@533
  return solaris_mprotect(addr, bytes, PROT_READ|PROT_WRITE);
duke@0
}
duke@0
duke@0
// Large page support
duke@0
duke@0
// UseLargePages is the master flag to enable/disable large page memory.
duke@0
// UseMPSS and UseISM are supported for compatibility reasons. Their combined
duke@0
// effects can be described in the following table:
duke@0
//
duke@0
// UseLargePages UseMPSS UseISM
duke@0
//    false         *       *   => UseLargePages is the master switch, turning
duke@0
//                                 it off will turn off both UseMPSS and
duke@0
//                                 UseISM. VM will not use large page memory
duke@0
//                                 regardless the settings of UseMPSS/UseISM.
duke@0
//     true      false    false => Unless future Solaris provides other
duke@0
//                                 mechanism to use large page memory, this
duke@0
//                                 combination is equivalent to -UseLargePages,
duke@0
//                                 VM will not use large page memory
duke@0
//     true      true     false => JVM will use MPSS for large page memory.
duke@0
//                                 This is the default behavior.
duke@0
//     true      false    true  => JVM will use ISM for large page memory.
duke@0
//     true      true     true  => JVM will use ISM if it is available.
duke@0
//                                 Otherwise, JVM will fall back to MPSS.
duke@0
//                                 Becaues ISM is now available on all
duke@0
//                                 supported Solaris versions, this combination
duke@0
//                                 is equivalent to +UseISM -UseMPSS.
duke@0
duke@0
typedef int (*getpagesizes_func_type) (size_t[], int);
duke@0
static size_t _large_page_size = 0;
duke@0
duke@0
bool os::Solaris::ism_sanity_check(bool warn, size_t * page_size) {
duke@0
  // x86 uses either 2M or 4M page, depending on whether PAE (Physical Address
duke@0
  // Extensions) mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. Sparc
duke@0
  // can support multiple page sizes.
duke@0
duke@0
  // Don't bother to probe page size because getpagesizes() comes with MPSS.
duke@0
  // ISM is only recommended on old Solaris where there is no MPSS support.
duke@0
  // Simply choose a conservative value as default.
duke@0
  *page_size = LargePageSizeInBytes ? LargePageSizeInBytes :
bobv@1892
               SPARC_ONLY(4 * M) IA32_ONLY(4 * M) AMD64_ONLY(2 * M)
bobv@1892
               ARM_ONLY(2 * M);
duke@0
duke@0
  // ISM is available on all supported Solaris versions
duke@0
  return true;
duke@0
}
duke@0
duke@0
// Insertion sort for small arrays (descending order).
duke@0
static void insertion_sort_descending(size_t* array, int len) {
duke@0
  for (int i = 0; i < len; i++) {
duke@0
    size_t val = array[i];
duke@0
    for (size_t key = i; key > 0 && array[key - 1] < val; --key) {
duke@0
      size_t tmp = array[key];
duke@0
      array[key] = array[key - 1];
duke@0
      array[key - 1] = tmp;
duke@0
    }
duke@0
  }
duke@0
}
duke@0
duke@0
bool os::Solaris::mpss_sanity_check(bool warn, size_t * page_size) {
duke@0
  getpagesizes_func_type getpagesizes_func =
duke@0
    CAST_TO_FN_PTR(getpagesizes_func_type, dlsym(RTLD_DEFAULT, "getpagesizes"));
duke@0
  if (getpagesizes_func == NULL) {
duke@0
    if (warn) {
duke@0
      warning("MPSS is not supported by the operating system.");
duke@0
    }
duke@0
    return false;
duke@0
  }
duke@0
duke@0
  const unsigned int usable_count = VM_Version::page_size_count();
duke@0
  if (usable_count == 1) {
duke@0
    return false;
duke@0
  }
duke@0
duke@0
  // Fill the array of page sizes.
duke@0
  int n = getpagesizes_func(_page_sizes, page_sizes_max);
duke@0
  assert(n > 0, "Solaris bug?");
duke@0
  if (n == page_sizes_max) {
duke@0
    // Add a sentinel value (necessary only if the array was completely filled
duke@0
    // since it is static (zeroed at initialization)).
duke@0
    _page_sizes[--n] = 0;
duke@0
    DEBUG_ONLY(warning("increase the size of the os::_page_sizes array.");)
duke@0
  }
duke@0
  assert(_page_sizes[n] == 0, "missing sentinel");
duke@0
duke@0
  if (n == 1) return false;     // Only one page size available.
duke@0
duke@0
  // Skip sizes larger than 4M (or LargePageSizeInBytes if it was set) and
duke@0
  // select up to usable_count elements.  First sort the array, find the first
duke@0
  // acceptable value, then copy the usable sizes to the top of the array and
duke@0
  // trim the rest.  Make sure to include the default page size :-).
duke@0
  //
duke@0
  // A better policy could get rid of the 4M limit by taking the sizes of the
duke@0
  // important VM memory regions (java heap and possibly the code cache) into
duke@0
  // account.
duke@0
  insertion_sort_descending(_page_sizes, n);
duke@0
  const size_t size_limit =
duke@0
    FLAG_IS_DEFAULT(LargePageSizeInBytes) ? 4 * M : LargePageSizeInBytes;
duke@0
  int beg;
duke@0
  for (beg = 0; beg < n && _page_sizes[beg] > size_limit; ++beg) /* empty */ ;
duke@0
  const int end = MIN2((int)usable_count, n) - 1;
duke@0
  for (int cur = 0; cur < end; ++cur, ++beg) {
duke@0
    _page_sizes[cur] = _page_sizes[beg];
duke@0
  }
duke@0
  _page_sizes[end] = vm_page_size();
duke@0
  _page_sizes[end + 1] = 0;
duke@0
duke@0
  if (_page_sizes[end] > _page_sizes[end - 1]) {
duke@0
    // Default page size is not the smallest; sort again.
duke@0
    insertion_sort_descending(_page_sizes, end + 1);
duke@0
  }
duke@0
  *page_size = _page_sizes[0];
duke@0
duke@0
  return true;
duke@0
}
duke@0
duke@0
bool os::large_page_init() {
duke@0
  if (!UseLargePages) {
duke@0
    UseISM = false;
duke@0
    UseMPSS = false;
duke@0
    return false;
duke@0
  }
duke@0
duke@0
  // print a warning if any large page related flag is specified on command line
duke@0
  bool warn_on_failure = !FLAG_IS_DEFAULT(UseLargePages)        ||
duke@0
                         !FLAG_IS_DEFAULT(UseISM)               ||
duke@0
                         !FLAG_IS_DEFAULT(UseMPSS)              ||
duke@0
                         !FLAG_IS_DEFAULT(LargePageSizeInBytes);
duke@0
  UseISM = UseISM &&
duke@0
           Solaris::ism_sanity_check(warn_on_failure, &_large_page_size);
duke@0
  if (UseISM) {
duke@0
    // ISM disables MPSS to be compatible with old JDK behavior
duke@0
    UseMPSS = false;
jcoomes@137
    _page_sizes[0] = _large_page_size;
jcoomes@137
    _page_sizes[1] = vm_page_size();
duke@0
  }
duke@0
duke@0
  UseMPSS = UseMPSS &&
duke@0
            Solaris::mpss_sanity_check(warn_on_failure, &_large_page_size);
duke@0
duke@0
  UseLargePages = UseISM || UseMPSS;
duke@0
  return UseLargePages;
duke@0
}
duke@0
duke@0
bool os::Solaris::set_mpss_range(caddr_t start, size_t bytes, size_t align) {
duke@0
  // Signal to OS that we want large pages for addresses
duke@0
  // from addr, addr + bytes
duke@0
  struct memcntl_mha mpss_struct;
duke@0
  mpss_struct.mha_cmd = MHA_MAPSIZE_VA;
duke@0
  mpss_struct.mha_pagesize = align;
duke@0
  mpss_struct.mha_flags = 0;
duke@0
  if (memcntl(start, bytes, MC_HAT_ADVISE,
duke@0
              (caddr_t) &mpss_struct, 0, 0) < 0) {
duke@0
    debug_only(warning("Attempt to use MPSS failed."));
duke@0
    return false;
duke@0
  }
duke@0
  return true;
duke@0
}
duke@0
coleenp@783
char* os::reserve_memory_special(size_t bytes, char* 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 && UseISM, "only for ISM large pages");
duke@0
duke@0
  size_t size = bytes;
duke@0
  char* retAddr = NULL;
duke@0
  int shmid;
duke@0
  key_t ismKey;
duke@0
duke@0
  bool warn_on_failure = UseISM &&
duke@0
                        (!FLAG_IS_DEFAULT(UseLargePages)         ||
duke@0
                         !FLAG_IS_DEFAULT(UseISM)                ||
duke@0
                         !FLAG_IS_DEFAULT(LargePageSizeInBytes)
duke@0
                        );
duke@0
  char msg[128];
duke@0
duke@0
  ismKey = IPC_PRIVATE;
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
  shmid = shmget(ismKey, size, SHM_R | SHM_W | IPC_CREAT);
duke@0
  if (shmid == -1){
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
duke@0
  retAddr = (char *) shmat(shmid, 0, SHM_SHARE_MMU | SHM_R | SHM_W);
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 (retAddr == (char *) -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 retAddr;
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
// MPSS allows application to commit large page memory on demand; with ISM
duke@0
// the entire memory region must be allocated as shared memory.
duke@0
bool os::can_commit_large_page_memory() {
jcoomes@137
  return UseISM ? false : true;
jcoomes@137
}
jcoomes@137
jcoomes@137
bool os::can_execute_large_page_memory() {
duke@0
  return UseISM ? false : true;
duke@0
}
duke@0
duke@0
static int os_sleep(jlong millis, bool interruptible) {
duke@0
  const jlong limit = INT_MAX;
duke@0
  jlong prevtime;
duke@0
  int res;
duke@0
duke@0
  while (millis > limit) {
duke@0
    if ((res = os_sleep(limit, interruptible)) != OS_OK)
duke@0
      return res;
duke@0
    millis -= limit;
duke@0
  }
duke@0
duke@0
  // Restart interrupted polls with new parameters until the proper delay
duke@0
  // has been completed.
duke@0
duke@0
  prevtime = getTimeMillis();
duke@0
duke@0
  while (millis > 0) {
duke@0
    jlong newtime;
duke@0
duke@0
    if (!interruptible) {
duke@0
      // Following assert fails for os::yield_all:
duke@0
      // assert(!thread->is_Java_thread(), "must not be java thread");
duke@0
      res = poll(NULL, 0, millis);
duke@0
    } else {
duke@0
      JavaThread *jt = JavaThread::current();
duke@0
duke@0
      INTERRUPTIBLE_NORESTART_VM_ALWAYS(poll(NULL, 0, millis), res, jt,
duke@0
        os::Solaris::clear_interrupted);
duke@0
    }
duke@0
duke@0
    // INTERRUPTIBLE_NORESTART_VM_ALWAYS returns res == OS_INTRPT for
duke@0
    // thread.Interrupt.
duke@0
duke@0
    if((res == OS_ERR) && (errno == EINTR)) {
duke@0
      newtime = getTimeMillis();
duke@0
      assert(newtime >= prevtime, "time moving backwards");
duke@0
    /* Doing prevtime and newtime in microseconds doesn't help precision,
duke@0
       and trying to round up to avoid lost milliseconds can result in a
duke@0
       too-short delay. */
duke@0
      millis -= newtime - prevtime;
duke@0
      if(millis <= 0)
duke@0
        return OS_OK;
duke@0
      prevtime = newtime;
duke@0
    } else
duke@0
      return res;
duke@0
  }
duke@0
duke@0
  return OS_OK;
duke@0
}
duke@0
duke@0
// Read calls from inside the vm need to perform state transitions
duke@0
size_t os::read(int fd, void *buf, unsigned int nBytes) {
duke@0
  INTERRUPTIBLE_RETURN_INT_VM(::read(fd, buf, nBytes), os::Solaris::clear_interrupted);
duke@0
}
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
  // TODO-FIXME: this should be removed.
duke@0
  // On Solaris machines (especially 2.5.1) we found that sometimes the VM gets into a live lock
duke@0
  // situation with a JavaThread being starved out of a lwp. The kernel doesn't seem to generate
duke@0
  // a SIGWAITING signal which would enable the threads library to create a new lwp for the starving
duke@0
  // thread. We suspect that because the Watcher thread keeps waking up at periodic intervals the kernel
duke@0
  // is fooled into believing that the system is making progress. In the code below we block the
duke@0
  // the watcher thread while safepoint is in progress so that it would not appear as though the
duke@0
  // system is making progress.
duke@0
  if (!Solaris::T2_libthread() &&
duke@0
      thread->is_Watcher_thread() && SafepointSynchronize::is_synchronizing() && !Arguments::has_profile()) {
duke@0
    // We now try to acquire the threads lock. Since this lock is held by the VM thread during
duke@0
    // the entire safepoint, the watcher thread will  line up here during the safepoint.
duke@0
    Threads_lock->lock_without_safepoint_check();
duke@0
    Threads_lock->unlock();
duke@0
  }
duke@0
duke@0
  if (thread->is_Java_thread()) {
duke@0
    // This is a JavaThread so we honor the _thread_blocked protocol
duke@0
    // even for sleeps of 0 milliseconds. This was originally done
duke@0
    // as a workaround for bug 4338139. However, now we also do it
duke@0
    // to honor the suspend-equivalent protocol.
duke@0
duke@0
    JavaThread *jt = (JavaThread *) thread;
duke@0
    ThreadBlockInVM tbivm(jt);
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
    int ret_code;
duke@0
    if (millis <= 0) {
duke@0
      thr_yield();
duke@0
      ret_code = 0;
duke@0
    } else {
duke@0
      // The original sleep() implementation did not create an
duke@0
      // OSThreadWaitState helper for sleeps of 0 milliseconds.
duke@0
      // I'm preserving that decision for now.
duke@0
      OSThreadWaitState osts(jt->osthread(), false /* not Object.wait() */);
duke@0
duke@0
      ret_code = os_sleep(millis, interruptible);
duke@0
    }
duke@0
duke@0
    // were we externally suspended while we were waiting?
duke@0
    jt->check_and_wait_while_suspended();
duke@0
duke@0
    return ret_code;
duke@0
  }
duke@0
duke@0
  // non-JavaThread from this point on:
duke@0
duke@0
  if (millis <= 0) {
duke@0
    thr_yield();
duke@0
    return 0;
duke@0
  }
duke@0
duke@0
  OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
duke@0
duke@0
  return os_sleep(millis, interruptible);
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(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
  if (DontYieldALot) {
duke@0
    static hrtime_t last_time = 0;
duke@0
    hrtime_t diff = getTimeNanos() - last_time;
duke@0
duke@0
    if (diff < DontYieldALotInterval * 1000000)
duke@0
      return true;
duke@0
duke@0
    last_time += diff;
duke@0
duke@0
    return false;
duke@0
  }
duke@0
  else {
duke@0
    return false;
duke@0
  }
duke@0
}
duke@0
duke@0
// Caveat: Solaris os::yield() causes a thread-state transition whereas
duke@0
// the linux and win32 implementations do not.  This should be checked.
duke@0
duke@0
void os::yield() {
duke@0
  // Yields to all threads with same or greater priority
duke@0
  os::sleep(Thread::current(), 0, false);
duke@0
}
duke@0
duke@0
// Note that yield semantics are defined by the scheduling class to which
duke@0
// the thread currently belongs.  Typically, yield will _not yield to
duke@0
// other equal or higher priority threads that reside on the dispatch queues
duke@0
// of other CPUs.
duke@0
duke@0
os::YieldResult os::NakedYield() { thr_yield(); return os::YIELD_UNKNOWN; }
duke@0
duke@0
duke@0
// On Solaris we found that yield_all doesn't always yield to all other threads.
duke@0
// There have been cases where there is a thread ready to execute but it doesn't
duke@0
// get an lwp as the VM thread continues to spin with sleeps of 1 millisecond.
duke@0
// The 1 millisecond wait doesn't seem long enough for the kernel to issue a
duke@0
// SIGWAITING signal which will cause a new lwp to be created. So we count the
duke@0
// number of times yield_all is called in the one loop and increase the sleep
duke@0
// time after 8 attempts. If this fails too we increase the concurrency level
duke@0
// so that the starving thread would get an lwp
duke@0
duke@0
void os::yield_all(int attempts) {
duke@0
  // Yields to all threads, including threads with lower priorities
duke@0
  if (attempts == 0) {
duke@0
    os::sleep(Thread::current(), 1, false);
duke@0
  } else {
duke@0
    int iterations = attempts % 30;
duke@0
    if (iterations == 0 && !os::Solaris::T2_libthread()) {
duke@0
      // thr_setconcurrency and _getconcurrency make sense only under T1.
duke@0
      int noofLWPS = thr_getconcurrency();
duke@0
      if (noofLWPS < (Threads::number_of_threads() + 2)) {
duke@0
        thr_setconcurrency(thr_getconcurrency() + 1);
duke@0
      }
duke@0
    } else if (iterations < 25) {
duke@0
      os::sleep(Thread::current(), 1, false);
duke@0
    } else {
duke@0
      os::sleep(Thread::current(), 10, false);
duke@0
    }
duke@0
  }
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
// Interface for setting lwp priorities.  If we are using T2 libthread,
duke@0
// which forces the use of BoundThreads or we manually set UseBoundThreads,
duke@0
// all of our threads will be assigned to real lwp's.  Using the thr_setprio
duke@0
// function is meaningless in this mode so we must adjust the real lwp's priority
duke@0
// The routines below implement the getting and setting of lwp priorities.
duke@0
//
duke@0
// Note: There are three priority scales used on Solaris.  Java priotities
duke@0
//       which range from 1 to 10, libthread "thr_setprio" scale which range
duke@0
//       from 0 to 127, and the current scheduling class of the process we
duke@0
//       are running in.  This is typically from -60 to +60.
duke@0
//       The setting of the lwp priorities in done after a call to thr_setprio
duke@0
//       so Java priorities are mapped to libthread priorities and we map from
duke@0
//       the latter to lwp priorities.  We don't keep priorities stored in
duke@0
//       Java priorities since some of our worker threads want to set priorities
duke@0
//       higher than all Java threads.
duke@0
//
duke@0
// For related information:
duke@0
// (1)  man -s 2 priocntl
duke@0
// (2)  man -s 4 priocntl
duke@0
// (3)  man dispadmin
duke@0
// =    librt.so
duke@0
// =    libthread/common/rtsched.c - thrp_setlwpprio().
duke@0
// =    ps -cL <pid> ... to validate priority.
duke@0
// =    sched_get_priority_min and _max
duke@0
//              pthread_create
duke@0
//              sched_setparam
duke@0
//              pthread_setschedparam
duke@0
//
duke@0
// Assumptions:
duke@0
// +    We assume that all threads in the process belong to the same
duke@0
//              scheduling class.   IE. an homogenous process.
duke@0
// +    Must be root or in IA group to change change "interactive" attribute.
duke@0
//              Priocntl() will fail silently.  The only indication of failure is when
duke@0
//              we read-back the value and notice that it hasn't changed.
duke@0
// +    Interactive threads enter the runq at the head, non-interactive at the tail.
duke@0
// +    For RT, change timeslice as well.  Invariant:
duke@0
//              constant "priority integral"
duke@0
//              Konst == TimeSlice * (60-Priority)
duke@0
//              Given a priority, compute appropriate timeslice.
duke@0
// +    Higher numerical values have higher priority.
duke@0
duke@0
// sched class attributes
duke@0
typedef struct {
duke@0
        int   schedPolicy;              // classID
duke@0
        int   maxPrio;
duke@0
        int   minPrio;
duke@0
} SchedInfo;
duke@0
duke@0
duke@0
static SchedInfo tsLimits, iaLimits, rtLimits;
duke@0
duke@0
#ifdef ASSERT
duke@0
static int  ReadBackValidate = 1;
duke@0
#endif
duke@0
static int  myClass     = 0;
duke@0
static int  myMin       = 0;
duke@0
static int  myMax       = 0;
duke@0
static int  myCur       = 0;
duke@0
static bool priocntl_enable = false;
duke@0
duke@0
duke@0
// Call the version of priocntl suitable for all supported versions
duke@0
// of Solaris. We need to call through this wrapper so that we can
duke@0
// build on Solaris 9 and run on Solaris 8, 9 and 10.
duke@0
//
duke@0
// This code should be removed if we ever stop supporting Solaris 8
duke@0
// and earlier releases.
duke@0
duke@0
static long priocntl_stub(int pcver, idtype_t idtype, id_t id, int cmd, caddr_t arg);
duke@0
typedef long (*priocntl_type)(int pcver, idtype_t idtype, id_t id, int cmd, caddr_t arg);
duke@0
static priocntl_type priocntl_ptr = priocntl_stub;
duke@0
duke@0
// Stub to set the value of the real pointer, and then call the real
duke@0
// function.
duke@0
duke@0
static long priocntl_stub(int pcver, idtype_t idtype, id_t id, int cmd, caddr_t arg) {
duke@0
  // Try Solaris 8- name only.
duke@0
  priocntl_type tmp = (priocntl_type)dlsym(RTLD_DEFAULT, "__priocntl");
duke@0
  guarantee(tmp != NULL, "priocntl function not found.");
duke@0
  priocntl_ptr = tmp;
duke@0
  return (*priocntl_ptr)(PC_VERSION, idtype, id, cmd, arg);
duke@0
}
duke@0
duke@0
duke@0
// lwp_priocntl_init
duke@0
//
duke@0
// Try to determine the priority scale for our process.
duke@0
//
duke@0
// Return errno or 0 if OK.
duke@0
//
duke@0
static
duke@0
int     lwp_priocntl_init ()
duke@0
{
duke@0
  int rslt;
duke@0
  pcinfo_t ClassInfo;
duke@0
  pcparms_t ParmInfo;
duke@0
  int i;
duke@0
duke@0
  if (!UseThreadPriorities) return 0;
duke@0
duke@0
  // We are using Bound threads, we need to determine our priority ranges
duke@0
  if (os::Solaris::T2_libthread() || UseBoundThreads) {
duke@0
    // If ThreadPriorityPolicy is 1, switch tables
duke@0
    if (ThreadPriorityPolicy == 1) {
duke@0
      for (i = 0 ; i < MaxPriority+1; i++)
duke@0
        os::java_to_os_priority[i] = prio_policy1[i];
duke@0
    }
duke@0
  }
duke@0
  // Not using Bound Threads, set to ThreadPolicy 1
duke@0
  else {
duke@0
    for ( i = 0 ; i < MaxPriority+1; i++ ) {
duke@0
      os::java_to_os_priority[i] = prio_policy1[i];
duke@0
    }
duke@0
    return 0;
duke@0
  }
duke@0
duke@0
duke@0
  // Get IDs for a set of well-known scheduling classes.
duke@0
  // TODO-FIXME: GETCLINFO returns the current # of classes in the
duke@0
  // the system.  We should have a loop that iterates over the
duke@0
  // classID values, which are known to be "small" integers.
duke@0
duke@0
  strcpy(ClassInfo.pc_clname, "TS");
duke@0
  ClassInfo.pc_cid = -1;
duke@0
  rslt = (*priocntl_ptr)(PC_VERSION, P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
duke@0
  if (rslt < 0) return errno;
duke@0
  assert(ClassInfo.pc_cid != -1, "cid for TS class is -1");
duke@0
  tsLimits.schedPolicy = ClassInfo.pc_cid;
duke@0
  tsLimits.maxPrio = ((tsinfo_t*)ClassInfo.pc_clinfo)->ts_maxupri;
duke@0
  tsLimits.minPrio = -tsLimits.maxPrio;
duke@0
duke@0
  strcpy(ClassInfo.pc_clname, "IA");
duke@0
  ClassInfo.pc_cid = -1;
duke@0
  rslt = (*priocntl_ptr)(PC_VERSION, P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
duke@0
  if (rslt < 0) return errno;
duke@0
  assert(ClassInfo.pc_cid != -1, "cid for IA class is -1");
duke@0
  iaLimits.schedPolicy = ClassInfo.pc_cid;
duke@0
  iaLimits.maxPrio = ((iainfo_t*)ClassInfo.pc_clinfo)->ia_maxupri;
duke@0
  iaLimits.minPrio = -iaLimits.maxPrio;
duke@0
duke@0
  strcpy(ClassInfo.pc_clname, "RT");
duke@0
  ClassInfo.pc_cid = -1;
duke@0
  rslt = (*priocntl_ptr)(PC_VERSION, P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
duke@0
  if (rslt < 0) return errno;
duke@0
  assert(ClassInfo.pc_cid != -1, "cid for RT class is -1");
duke@0
  rtLimits.schedPolicy = ClassInfo.pc_cid;
duke@0
  rtLimits.maxPrio = ((rtinfo_t*)ClassInfo.pc_clinfo)->rt_maxpri;
duke@0
  rtLimits.minPrio = 0;
duke@0
duke@0
duke@0
  // Query our "current" scheduling class.
duke@0
  // This will normally be IA,TS or, rarely, RT.
duke@0
  memset (&ParmInfo, 0, sizeof(ParmInfo));
duke@0
  ParmInfo.pc_cid = PC_CLNULL;
duke@0
  rslt = (*priocntl_ptr) (PC_VERSION, P_PID, P_MYID, PC_GETPARMS, (caddr_t)&ParmInfo );
duke@0
  if ( rslt < 0 ) return errno;
duke@0
  myClass = ParmInfo.pc_cid;
duke@0
duke@0
  // We now know our scheduling classId, get specific information
duke@0
  // the class.
duke@0
  ClassInfo.pc_cid = myClass;
duke@0
  ClassInfo.pc_clname[0] = 0;
duke@0
  rslt = (*priocntl_ptr) (PC_VERSION, (idtype)0, 0, PC_GETCLINFO, (caddr_t)&ClassInfo );
duke@0
  if ( rslt < 0 ) return errno;
duke@0
duke@0
  if (ThreadPriorityVerbose)
duke@0
    tty->print_cr ("lwp_priocntl_init: Class=%d(%s)...", myClass, ClassInfo.pc_clname);
duke@0
duke@0
  memset(&ParmInfo, 0, sizeof(pcparms_t));
duke@0
  ParmInfo.pc_cid = PC_CLNULL;
duke@0
  rslt = (*priocntl_ptr)(PC_VERSION, P_PID, P_MYID, PC_GETPARMS, (caddr_t)&ParmInfo);
duke@0
  if (rslt < 0) return errno;
duke@0
duke@0
  if (ParmInfo.pc_cid == rtLimits.schedPolicy) {
duke@0
    myMin = rtLimits.minPrio;
duke@0
    myMax = rtLimits.maxPrio;
duke@0
  } else if (ParmInfo.pc_cid == iaLimits.schedPolicy) {
duke@0
    iaparms_t *iaInfo  = (iaparms_t*)ParmInfo.pc_clparms;
duke@0
    myMin = iaLimits.minPrio;
duke@0
    myMax = iaLimits.maxPrio;
duke@0
    myMax = MIN2(myMax, (int)iaInfo->ia_uprilim);       // clamp - restrict
duke@0
  } else if (ParmInfo.pc_cid == tsLimits.schedPolicy) {
duke@0
    tsparms_t *tsInfo  = (tsparms_t*)ParmInfo.pc_clparms;
duke@0
    myMin = tsLimits.minPrio;
duke@0
    myMax = tsLimits.maxPrio;
duke@0
    myMax = MIN2(myMax, (int)tsInfo->ts_uprilim);       // clamp - restrict
duke@0
  } else {
duke@0
    // No clue - punt
duke@0
    if (ThreadPriorityVerbose)
duke@0
      tty->print_cr ("Unknown scheduling class: %s ... \n", ClassInfo.pc_clname);
duke@0
    return EINVAL;      // no clue, punt
duke@0
  }
duke@0
duke@0
  if (ThreadPriorityVerbose)
duke@0
        tty->print_cr ("Thread priority Range: [%d..%d]\n", myMin, myMax);
duke@0
duke@0
  priocntl_enable = true;  // Enable changing priorities
duke@0
  return 0;
duke@0
}
duke@0
duke@0
#define IAPRI(x)        ((iaparms_t *)((x).pc_clparms))
duke@0
#define RTPRI(x)        ((rtparms_t *)((x).pc_clparms))
duke@0
#define TSPRI(x)        ((tsparms_t *)((x).pc_clparms))
duke@0
duke@0
duke@0
// scale_to_lwp_priority
duke@0
//
duke@0
// Convert from the libthread "thr_setprio" scale to our current
duke@0
// lwp scheduling class scale.
duke@0
//
duke@0
static
duke@0
int     scale_to_lwp_priority (int rMin, int rMax, int x)
duke@0
{
duke@0
  int v;
duke@0
duke@0
  if (x == 127) return rMax;            // avoid round-down
duke@0
    v = (((x*(rMax-rMin)))/128)+rMin;
duke@0
  return v;
duke@0
}
duke@0
duke@0
duke@0
// set_lwp_priority
duke@0
//
duke@0
// Set the priority of the lwp.  This call should only be made
duke@0
// when using bound threads (T2 threads are bound by default).
duke@0
//
duke@0
int     set_lwp_priority (int ThreadID, int lwpid, int newPrio )
duke@0
{
duke@0
  int rslt;
duke@0
  int Actual, Expected, prv;
duke@0
  pcparms_t ParmInfo;                   // for GET-SET
duke@0
#ifdef ASSERT
duke@0
  pcparms_t ReadBack;