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