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 }