src/os/solaris/vm/osThread_solaris.cpp

Thu, 27 May 2010 19:08:38 -0700

author
trims
date
Thu, 27 May 2010 19:08:38 -0700
changeset 1907
c18cbe5936b8
parent 772
9ee9cf798b59
child 2314
f95d63e2154a
permissions
-rw-r--r--

6941466: Oracle rebranding changes for Hotspot repositories
Summary: Change all the Sun copyrights to Oracle copyright
Reviewed-by: ohair

     1 /*
     2  * Copyright (c) 1998, 2008, 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 // do not include  precompiled  header file
    26 # include "incls/_osThread_solaris.cpp.incl"
    27 # include <signal.h>
    29  // ***************************************************************
    30  // Platform dependent initialization and cleanup
    31  // ***************************************************************
    33 void OSThread::pd_initialize() {
    34   _thread_id                         = 0;
    35   sigemptyset(&_caller_sigmask);
    37   _current_callback                  = NULL;
    38   _current_callback_lock = VM_Version::supports_compare_and_exchange() ? NULL
    39                     : new Mutex(Mutex::suspend_resume, "Callback_lock", true);
    41   _saved_interrupt_thread_state      = _thread_new;
    42   _vm_created_thread                 = false;
    43 }
    45 void OSThread::pd_destroy() {
    46 }
    48 // Synchronous interrupt support
    49 //
    50 // _current_callback == NULL          no pending callback
    51 //                   == 1             callback_in_progress
    52 //                   == other value   pointer to the pending callback
    53 //
    55 // CAS on v8 is implemented by using a global atomic_memory_operation_lock,
    56 // which is shared by other atomic functions. It is OK for normal uses, but
    57 // dangerous if used after some thread is suspended or if used in signal
    58 // handlers. Instead here we use a special per-thread lock to synchronize
    59 // updating _current_callback if we are running on v8. Note in general trying
    60 // to grab locks after a thread is suspended is not safe, but it is safe for
    61 // updating _current_callback, because synchronous interrupt callbacks are
    62 // currently only used in:
    63 // 1. GetThreadPC_Callback - used by WatcherThread to profile VM thread
    64 // There is no overlap between the callbacks, which means we won't try to
    65 // grab a thread's sync lock after the thread has been suspended while holding
    66 // the same lock.
    68 // used after a thread is suspended
    69 static intptr_t compare_and_exchange_current_callback (
    70        intptr_t callback, intptr_t *addr, intptr_t compare_value, Mutex *sync) {
    71   if (VM_Version::supports_compare_and_exchange()) {
    72     return Atomic::cmpxchg_ptr(callback, addr, compare_value);
    73   } else {
    74     MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
    75     if (*addr == compare_value) {
    76       *addr = callback;
    77       return compare_value;
    78     } else {
    79       return callback;
    80     }
    81   }
    82 }
    84 // used in signal handler
    85 static intptr_t exchange_current_callback(intptr_t callback, intptr_t *addr, Mutex *sync) {
    86   if (VM_Version::supports_compare_and_exchange()) {
    87     return Atomic::xchg_ptr(callback, addr);
    88   } else {
    89     MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
    90     intptr_t cb = *addr;
    91     *addr = callback;
    92     return cb;
    93   }
    94 }
    96 // one interrupt at a time. spin if _current_callback != NULL
    97 int OSThread::set_interrupt_callback(Sync_Interrupt_Callback * cb) {
    98   int count = 0;
    99   while (compare_and_exchange_current_callback(
   100          (intptr_t)cb, (intptr_t *)&_current_callback, (intptr_t)NULL, _current_callback_lock) != NULL) {
   101     while (_current_callback != NULL) {
   102       count++;
   103 #ifdef ASSERT
   104       if ((WarnOnStalledSpinLock > 0) &&
   105           (count % WarnOnStalledSpinLock == 0)) {
   106           warning("_current_callback seems to be stalled: %p", _current_callback);
   107       }
   108 #endif
   109       os::yield_all(count);
   110     }
   111   }
   112   return 0;
   113 }
   115 // reset _current_callback, spin if _current_callback is callback_in_progress
   116 void OSThread::remove_interrupt_callback(Sync_Interrupt_Callback * cb) {
   117   int count = 0;
   118   while (compare_and_exchange_current_callback(
   119          (intptr_t)NULL, (intptr_t *)&_current_callback, (intptr_t)cb, _current_callback_lock) != (intptr_t)cb) {
   120 #ifdef ASSERT
   121     intptr_t p = (intptr_t)_current_callback;
   122     assert(p == (intptr_t)callback_in_progress ||
   123            p == (intptr_t)cb, "wrong _current_callback value");
   124 #endif
   125     while (_current_callback != cb) {
   126       count++;
   127 #ifdef ASSERT
   128       if ((WarnOnStalledSpinLock > 0) &&
   129           (count % WarnOnStalledSpinLock == 0)) {
   130           warning("_current_callback seems to be stalled: %p", _current_callback);
   131       }
   132 #endif
   133       os::yield_all(count);
   134     }
   135   }
   136 }
   138 void OSThread::do_interrupt_callbacks_at_interrupt(InterruptArguments *args) {
   139   Sync_Interrupt_Callback * cb;
   140   cb = (Sync_Interrupt_Callback *)exchange_current_callback(
   141         (intptr_t)callback_in_progress, (intptr_t *)&_current_callback, _current_callback_lock);
   143   if (cb == NULL) {
   144     // signal is delivered too late (thread is masking interrupt signal??).
   145     // there is nothing we need to do because requesting thread has given up.
   146   } else if ((intptr_t)cb == (intptr_t)callback_in_progress) {
   147     fatal("invalid _current_callback state");
   148   } else {
   149     assert(cb->target()->osthread() == this, "wrong target");
   150     cb->execute(args);
   151     cb->leave_callback();             // notify the requester
   152   }
   154   // restore original _current_callback value
   155   intptr_t p;
   156   p = exchange_current_callback((intptr_t)cb, (intptr_t *)&_current_callback, _current_callback_lock);
   157   assert(p == (intptr_t)callback_in_progress, "just checking");
   158 }
   160 // Called by the requesting thread to send a signal to target thread and
   161 // execute "this" callback from the signal handler.
   162 int OSThread::Sync_Interrupt_Callback::interrupt(Thread * target, int timeout) {
   163   // Let signals to the vm_thread go even if the Threads_lock is not acquired
   164   assert(Threads_lock->owned_by_self() || (target == VMThread::vm_thread()),
   165          "must have threads lock to call this");
   167   OSThread * osthread = target->osthread();
   169   // may block if target thread already has a pending callback
   170   osthread->set_interrupt_callback(this);
   172   _target = target;
   174   int rslt = thr_kill(osthread->thread_id(), os::Solaris::SIGasync());
   175   assert(rslt == 0, "thr_kill != 0");
   177   bool status = false;
   178   jlong t1 = os::javaTimeMillis();
   179   { // don't use safepoint check because we might be the watcher thread.
   180     MutexLockerEx ml(_sync, Mutex::_no_safepoint_check_flag);
   181     while (!is_done()) {
   182       status = _sync->wait(Mutex::_no_safepoint_check_flag, timeout);
   184       // status == true if timed out
   185       if (status) break;
   187       // update timeout
   188       jlong t2 = os::javaTimeMillis();
   189       timeout -= t2 - t1;
   190       t1 = t2;
   191     }
   192   }
   194   // reset current_callback
   195   osthread->remove_interrupt_callback(this);
   197   return status;
   198 }
   200 void OSThread::Sync_Interrupt_Callback::leave_callback() {
   201   if (!_sync->owned_by_self()) {
   202     // notify requesting thread
   203     MutexLockerEx ml(_sync, Mutex::_no_safepoint_check_flag);
   204     _is_done = true;
   205     _sync->notify_all();
   206   } else {
   207     // Current thread is interrupted while it is holding the _sync lock, trying
   208     // to grab it again will deadlock. The requester will timeout anyway,
   209     // so just return.
   210     _is_done = true;
   211   }
   212 }
   214 // copied from synchronizer.cpp
   216 void OSThread::handle_spinlock_contention(int tries) {
   217   if (NoYieldsInMicrolock) return;
   219   if (tries > 10) {
   220     os::yield_all(tries); // Yield to threads of any priority
   221   } else if (tries > 5) {
   222     os::yield();          // Yield to threads of same or higher priority
   223   }
   224 }

mercurial