osThread_solaris.cpp revision 1472:c18cbe5936b8
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 */ 24 25// do not include precompiled header file 26# include "incls/_osThread_solaris.cpp.incl" 27# include <signal.h> 28 29 // *************************************************************** 30 // Platform dependent initialization and cleanup 31 // *************************************************************** 32 33void OSThread::pd_initialize() { 34 _thread_id = 0; 35 sigemptyset(&_caller_sigmask); 36 37 _current_callback = NULL; 38 _current_callback_lock = VM_Version::supports_compare_and_exchange() ? NULL 39 : new Mutex(Mutex::suspend_resume, "Callback_lock", true); 40 41 _saved_interrupt_thread_state = _thread_new; 42 _vm_created_thread = false; 43} 44 45void OSThread::pd_destroy() { 46} 47 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// 54 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. 67 68// used after a thread is suspended 69static 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} 83 84// used in signal handler 85static 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} 95 96// one interrupt at a time. spin if _current_callback != NULL 97int 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} 114 115// reset _current_callback, spin if _current_callback is callback_in_progress 116void 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} 137 138void 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); 142 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 } 153 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} 159 160// Called by the requesting thread to send a signal to target thread and 161// execute "this" callback from the signal handler. 162int 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"); 166 167 OSThread * osthread = target->osthread(); 168 169 // may block if target thread already has a pending callback 170 osthread->set_interrupt_callback(this); 171 172 _target = target; 173 174 int rslt = thr_kill(osthread->thread_id(), os::Solaris::SIGasync()); 175 assert(rslt == 0, "thr_kill != 0"); 176 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); 183 184 // status == true if timed out 185 if (status) break; 186 187 // update timeout 188 jlong t2 = os::javaTimeMillis(); 189 timeout -= t2 - t1; 190 t1 = t2; 191 } 192 } 193 194 // reset current_callback 195 osthread->remove_interrupt_callback(this); 196 197 return status; 198} 199 200void 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} 213 214// copied from synchronizer.cpp 215 216void OSThread::handle_spinlock_contention(int tries) { 217 if (NoYieldsInMicrolock) return; 218 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} 225