src/os/solaris/vm/osThread_solaris.cpp

Wed, 27 Mar 2013 19:21:18 +0100

author
tschatzl
date
Wed, 27 Mar 2013 19:21:18 +0100
changeset 4854
754c24457b20
parent 4318
cd3d6a6b95d9
child 5237
f2110083203d
permissions
-rw-r--r--

7112912: Message "Error occurred during initialization of VM" on boxes with lots of RAM
Summary: Ergonomics now also takes available virtual memory into account when deciding for a heap size. The helper method to determine the maximum allocatable memory block now uses the appropriate OS specific calls to retrieve available virtual memory for the java process. In 32 bit environments this method now also searches for the maximum actually reservable amount of memory. Merge previously separate implementations for Linux/BSD/Solaris into a single method.
Reviewed-by: jmasa, tamao

     1 /*
     2  * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    22  *
    23  */
    25 // no precompiled headers
    26 #include "runtime/atomic.hpp"
    27 #include "runtime/handles.inline.hpp"
    28 #include "runtime/mutexLocker.hpp"
    29 #include "runtime/os.hpp"
    30 #include "runtime/osThread.hpp"
    31 #include "runtime/safepoint.hpp"
    32 #include "runtime/vmThread.hpp"
    34 #include <signal.h>
    36  // ***************************************************************
    37  // Platform dependent initialization and cleanup
    38  // ***************************************************************
    40 void OSThread::pd_initialize() {
    41   _thread_id                         = 0;
    42   sigemptyset(&_caller_sigmask);
    44   _current_callback                  = NULL;
    45   _current_callback_lock = VM_Version::supports_compare_and_exchange() ? NULL
    46                     : new Mutex(Mutex::suspend_resume, "Callback_lock", true);
    48   _saved_interrupt_thread_state      = _thread_new;
    49   _vm_created_thread                 = false;
    50 }
    52 void OSThread::pd_destroy() {
    53 }
    55 // Synchronous interrupt support
    56 //
    57 // _current_callback == NULL          no pending callback
    58 //                   == 1             callback_in_progress
    59 //                   == other value   pointer to the pending callback
    60 //
    62 // CAS on v8 is implemented by using a global atomic_memory_operation_lock,
    63 // which is shared by other atomic functions. It is OK for normal uses, but
    64 // dangerous if used after some thread is suspended or if used in signal
    65 // handlers. Instead here we use a special per-thread lock to synchronize
    66 // updating _current_callback if we are running on v8. Note in general trying
    67 // to grab locks after a thread is suspended is not safe, but it is safe for
    68 // updating _current_callback, because synchronous interrupt callbacks are
    69 // currently only used in:
    70 // 1. GetThreadPC_Callback - used by WatcherThread to profile VM thread
    71 // There is no overlap between the callbacks, which means we won't try to
    72 // grab a thread's sync lock after the thread has been suspended while holding
    73 // the same lock.
    75 // used after a thread is suspended
    76 static intptr_t compare_and_exchange_current_callback (
    77        intptr_t callback, intptr_t *addr, intptr_t compare_value, Mutex *sync) {
    78   if (VM_Version::supports_compare_and_exchange()) {
    79     return Atomic::cmpxchg_ptr(callback, addr, compare_value);
    80   } else {
    81     MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
    82     if (*addr == compare_value) {
    83       *addr = callback;
    84       return compare_value;
    85     } else {
    86       return callback;
    87     }
    88   }
    89 }
    91 // used in signal handler
    92 static intptr_t exchange_current_callback(intptr_t callback, intptr_t *addr, Mutex *sync) {
    93   if (VM_Version::supports_compare_and_exchange()) {
    94     return Atomic::xchg_ptr(callback, addr);
    95   } else {
    96     MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
    97     intptr_t cb = *addr;
    98     *addr = callback;
    99     return cb;
   100   }
   101 }
   103 // one interrupt at a time. spin if _current_callback != NULL
   104 int OSThread::set_interrupt_callback(Sync_Interrupt_Callback * cb) {
   105   int count = 0;
   106   while (compare_and_exchange_current_callback(
   107          (intptr_t)cb, (intptr_t *)&_current_callback, (intptr_t)NULL, _current_callback_lock) != NULL) {
   108     while (_current_callback != NULL) {
   109       count++;
   110 #ifdef ASSERT
   111       if ((WarnOnStalledSpinLock > 0) &&
   112           (count % WarnOnStalledSpinLock == 0)) {
   113           warning("_current_callback seems to be stalled: %p", _current_callback);
   114       }
   115 #endif
   116       os::yield_all(count);
   117     }
   118   }
   119   return 0;
   120 }
   122 // reset _current_callback, spin if _current_callback is callback_in_progress
   123 void OSThread::remove_interrupt_callback(Sync_Interrupt_Callback * cb) {
   124   int count = 0;
   125   while (compare_and_exchange_current_callback(
   126          (intptr_t)NULL, (intptr_t *)&_current_callback, (intptr_t)cb, _current_callback_lock) != (intptr_t)cb) {
   127 #ifdef ASSERT
   128     intptr_t p = (intptr_t)_current_callback;
   129     assert(p == (intptr_t)callback_in_progress ||
   130            p == (intptr_t)cb, "wrong _current_callback value");
   131 #endif
   132     while (_current_callback != cb) {
   133       count++;
   134 #ifdef ASSERT
   135       if ((WarnOnStalledSpinLock > 0) &&
   136           (count % WarnOnStalledSpinLock == 0)) {
   137           warning("_current_callback seems to be stalled: %p", _current_callback);
   138       }
   139 #endif
   140       os::yield_all(count);
   141     }
   142   }
   143 }
   145 void OSThread::do_interrupt_callbacks_at_interrupt(InterruptArguments *args) {
   146   Sync_Interrupt_Callback * cb;
   147   cb = (Sync_Interrupt_Callback *)exchange_current_callback(
   148         (intptr_t)callback_in_progress, (intptr_t *)&_current_callback, _current_callback_lock);
   150   if (cb == NULL) {
   151     // signal is delivered too late (thread is masking interrupt signal??).
   152     // there is nothing we need to do because requesting thread has given up.
   153   } else if ((intptr_t)cb == (intptr_t)callback_in_progress) {
   154     fatal("invalid _current_callback state");
   155   } else {
   156     assert(cb->target()->osthread() == this, "wrong target");
   157     cb->execute(args);
   158     cb->leave_callback();             // notify the requester
   159   }
   161   // restore original _current_callback value
   162   intptr_t p;
   163   p = exchange_current_callback((intptr_t)cb, (intptr_t *)&_current_callback, _current_callback_lock);
   164   assert(p == (intptr_t)callback_in_progress, "just checking");
   165 }
   167 // Called by the requesting thread to send a signal to target thread and
   168 // execute "this" callback from the signal handler.
   169 int OSThread::Sync_Interrupt_Callback::interrupt(Thread * target, int timeout) {
   170   // Let signals to the vm_thread go even if the Threads_lock is not acquired
   171   assert(Threads_lock->owned_by_self() || (target == VMThread::vm_thread()),
   172          "must have threads lock to call this");
   174   OSThread * osthread = target->osthread();
   176   // may block if target thread already has a pending callback
   177   osthread->set_interrupt_callback(this);
   179   _target = target;
   181   int rslt = thr_kill(osthread->thread_id(), os::Solaris::SIGasync());
   182   assert(rslt == 0, "thr_kill != 0");
   184   bool status = false;
   185   jlong t1 = os::javaTimeMillis();
   186   { // don't use safepoint check because we might be the watcher thread.
   187     MutexLockerEx ml(_sync, Mutex::_no_safepoint_check_flag);
   188     while (!is_done()) {
   189       status = _sync->wait(Mutex::_no_safepoint_check_flag, timeout);
   191       // status == true if timed out
   192       if (status) break;
   194       // update timeout
   195       jlong t2 = os::javaTimeMillis();
   196       timeout -= t2 - t1;
   197       t1 = t2;
   198     }
   199   }
   201   // reset current_callback
   202   osthread->remove_interrupt_callback(this);
   204   return status;
   205 }
   207 void OSThread::Sync_Interrupt_Callback::leave_callback() {
   208   if (!_sync->owned_by_self()) {
   209     // notify requesting thread
   210     MutexLockerEx ml(_sync, Mutex::_no_safepoint_check_flag);
   211     _is_done = true;
   212     _sync->notify_all();
   213   } else {
   214     // Current thread is interrupted while it is holding the _sync lock, trying
   215     // to grab it again will deadlock. The requester will timeout anyway,
   216     // so just return.
   217     _is_done = true;
   218   }
   219 }
   221 // copied from synchronizer.cpp
   223 void OSThread::handle_spinlock_contention(int tries) {
   224   if (NoYieldsInMicrolock) return;
   226   if (tries > 10) {
   227     os::yield_all(tries); // Yield to threads of any priority
   228   } else if (tries > 5) {
   229     os::yield();          // Yield to threads of same or higher priority
   230   }
   231 }

mercurial