osThread_solaris.cpp revision 0:a61af66fc99e
1139804Simp/* 248391Speter * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. 348391Speter * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 448391Speter * 548391Speter * This code is free software; you can redistribute it and/or modify it 648391Speter * under the terms of the GNU General Public License version 2 only, as 748391Speter * published by the Free Software Foundation. 848391Speter * 948391Speter * This code is distributed in the hope that it will be useful, but WITHOUT 1048391Speter * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1148391Speter * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1248391Speter * version 2 for more details (a copy is included in the LICENSE file that 1348391Speter * accompanied this code). 1448391Speter * 1548391Speter * You should have received a copy of the GNU General Public License version 1648391Speter * 2 along with this work; if not, write to the Free Software Foundation, 1748391Speter * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1848391Speter * 1948391Speter * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 2048391Speter * CA 95054 USA or visit www.sun.com if you need additional information or 2148391Speter * have any questions. 2248391Speter * 2348391Speter */ 2448391Speter 2548391Speter// do not include precompiled header file 2648391Speter# include "incls/_osThread_solaris.cpp.incl" 27116182Sobrien# include <signal.h> 28116182Sobrien 29116182Sobrien // *************************************************************** 3048391Speter // Platform dependent initialization and cleanup 3148391Speter // *************************************************************** 3248391Speter 3370317Sjakevoid OSThread::pd_initialize() { 3474927Sjhb _thread_id = 0; 3574927Sjhb sigemptyset(&_caller_sigmask); 3655722Simp 3755539Sluoqi _current_callback = NULL; 3874927Sjhb _current_callback_lock = VM_Version::supports_compare_and_exchange() ? NULL 3948391Speter : new Mutex(Mutex::suspend_resume, "Callback_lock", true); 4048391Speter 41166188Sjeff _saved_interrupt_thread_state = _thread_new; 42173004Sjulian _vm_created_thread = false; 43173004Sjulian} 4448391Speter 4548391Spetervoid OSThread::pd_destroy() { 4648391Speter} 4748391Speter 4848391Speter// Synchronous interrupt support 4948391Speter// 5048391Speter// _current_callback == NULL no pending callback 5148391Speter// == 1 callback_in_progress 5248391Speter// == other value pointer to the pending callback 5348391Speter// 5448391Speter 5548391Speter// CAS on v8 is implemented by using a global atomic_memory_operation_lock, 5648391Speter// which is shared by other atomic functions. It is OK for normal uses, but 5748391Speter// dangerous if used after some thread is suspended or if used in signal 5848391Speter// handlers. Instead here we use a special per-thread lock to synchronize 5948391Speter// updating _current_callback if we are running on v8. Note in general trying 6048391Speter// to grab locks after a thread is suspended is not safe, but it is safe for 61172836Sjulian// updating _current_callback, because synchronous interrupt callbacks are 62104354Sscottl// currently only used in: 6348391Speter// 1. GetThreadPC_Callback - used by WatcherThread to profile VM thread 6448391Speter// There is no overlap between the callbacks, which means we won't try to 6548391Speter// grab a thread's sync lock after the thread has been suspended while holding 6648391Speter// the same lock. 6748391Speter 6865557Sjasone// used after a thread is suspended 6948391Speterstatic intptr_t compare_and_exchange_current_callback ( 7065557Sjasone intptr_t callback, intptr_t *addr, intptr_t compare_value, Mutex *sync) { 7165557Sjasone if (VM_Version::supports_compare_and_exchange()) { 7265557Sjasone return Atomic::cmpxchg_ptr(callback, addr, compare_value); 7365557Sjasone } else { 7465557Sjasone MutexLockerEx(sync, Mutex::_no_safepoint_check_flag); 7565557Sjasone if (*addr == compare_value) { 7648391Speter *addr = callback; 7748391Speter return compare_value; 78172836Sjulian } else { 79104354Sscottl return callback; 8048391Speter } 8148391Speter } 8248391Speter} 83103216Sjulian 8448391Speter// used in signal handler 8548391Speterstatic intptr_t exchange_current_callback(intptr_t callback, intptr_t *addr, Mutex *sync) { 86114434Sdes if (VM_Version::supports_compare_and_exchange()) { 87172836Sjulian return Atomic::xchg_ptr(callback, addr); 8865557Sjasone } else { 8990375Speter MutexLockerEx(sync, Mutex::_no_safepoint_check_flag); 90104354Sscottl intptr_t cb = *addr; 9148391Speter *addr = callback; 9248391Speter return cb; 9348391Speter } 9448391Speter} 9548391Speter 9648391Speter// one interrupt at a time. spin if _current_callback != NULL 9748391Speterint OSThread::set_interrupt_callback(Sync_Interrupt_Callback * cb) { 9848391Speter int count = 0; 9971559Sjhb while (compare_and_exchange_current_callback( 100173004Sjulian (intptr_t)cb, (intptr_t *)&_current_callback, (intptr_t)NULL, _current_callback_lock) != NULL) { 10171559Sjhb while (_current_callback != NULL) { 102173004Sjulian count++; 103114983Sjhb#ifdef ASSERT 104114983Sjhb if ((WarnOnStalledSpinLock > 0) && 105114983Sjhb (count % WarnOnStalledSpinLock == 0)) { 10671559Sjhb warning("_current_callback seems to be stalled: %p", _current_callback); 10748391Speter } 10848391Speter#endif 10948391Speter os::yield_all(count); 11048391Speter } 11148391Speter } 112173004Sjulian return 0; 113173004Sjulian} 114173004Sjulian 115173004Sjulian// reset _current_callback, spin if _current_callback is callback_in_progress 11648391Spetervoid OSThread::remove_interrupt_callback(Sync_Interrupt_Callback * cb) { 11748391Speter int count = 0; 118103216Sjulian while (compare_and_exchange_current_callback( 119103216Sjulian (intptr_t)NULL, (intptr_t *)&_current_callback, (intptr_t)cb, _current_callback_lock) != (intptr_t)cb) { 12048391Speter#ifdef ASSERT 12169657Sjhb intptr_t p = (intptr_t)_current_callback; 12269657Sjhb assert(p == (intptr_t)callback_in_progress || 123170307Sjeff p == (intptr_t)cb, "wrong _current_callback value"); 124166188Sjeff#endif 125170307Sjeff while (_current_callback != cb) { 12669657Sjhb count++; 12769657Sjhb#ifdef ASSERT 12848391Speter if ((WarnOnStalledSpinLock > 0) && 12948391Speter (count % WarnOnStalledSpinLock == 0)) { 13048391Speter warning("_current_callback seems to be stalled: %p", _current_callback); 13148391Speter } 132172836Sjulian#endif 13348391Speter os::yield_all(count); 13486293Speter } 13586293Speter } 13670317Sjake} 13786293Speter 13886293Spetervoid OSThread::do_interrupt_callbacks_at_interrupt(InterruptArguments *args) { 139155400Sjhb Sync_Interrupt_Callback * cb; 140155400Sjhb cb = (Sync_Interrupt_Callback *)exchange_current_callback( 141155400Sjhb (intptr_t)callback_in_progress, (intptr_t *)&_current_callback, _current_callback_lock); 142155400Sjhb 143155400Sjhb if (cb == NULL) { 14474927Sjhb // signal is delivered too late (thread is masking interrupt signal??). 14586292Sdillon // there is nothing we need to do because requesting thread has given up. 14686292Sdillon } else if ((intptr_t)cb == (intptr_t)callback_in_progress) { 14786292Sdillon fatal("invalid _current_callback state"); 14874927Sjhb } else { 149155400Sjhb assert(cb->target()->osthread() == this, "wrong target"); 150155400Sjhb cb->execute(args); 151155400Sjhb cb->leave_callback(); // notify the requester 152155400Sjhb } 153155400Sjhb 154155400Sjhb // restore original _current_callback value 155155400Sjhb intptr_t p; 15686293Speter p = exchange_current_callback((intptr_t)cb, (intptr_t *)&_current_callback, _current_callback_lock); 15748391Speter assert(p == (intptr_t)callback_in_progress, "just checking"); 15848391Speter} 15955539Sluoqi 16055539Sluoqi// Called by the requesting thread to send a signal to target thread and 16155539Sluoqi// execute "this" callback from the signal handler. 16255539Sluoqiint OSThread::Sync_Interrupt_Callback::interrupt(Thread * target, int timeout) { 16355539Sluoqi // Let signals to the vm_thread go even if the Threads_lock is not acquired 164172836Sjulian assert(Threads_lock->owned_by_self() || (target == VMThread::vm_thread()), 16555539Sluoqi "must have threads lock to call this"); 16655539Sluoqi 16755539Sluoqi OSThread * osthread = target->osthread(); 168104306Sjmallett 16955539Sluoqi // may block if target thread already has a pending callback 17073911Sjhb osthread->set_interrupt_callback(this); 17173911Sjhb 17273911Sjhb _target = target; 17355539Sluoqi 17473911Sjhb int rslt = thr_kill(osthread->thread_id(), os::Solaris::SIGasync()); 175104306Sjmallett assert(rslt == 0, "thr_kill != 0"); 17688160Speter 177173004Sjulian bool status = false; 17855539Sluoqi jlong t1 = os::javaTimeMillis(); 17955539Sluoqi { // don't use safepoint check because we might be the watcher thread. 18055539Sluoqi MutexLockerEx ml(_sync, Mutex::_no_safepoint_check_flag); 181172836Sjulian while (!is_done()) { 18255539Sluoqi status = _sync->wait(Mutex::_no_safepoint_check_flag, timeout); 18355539Sluoqi 18455539Sluoqi // status == true if timed out 18555539Sluoqi if (status) break; 18655539Sluoqi 18773911Sjhb // update timeout 18873911Sjhb jlong t2 = os::javaTimeMillis(); 18973911Sjhb timeout -= t2 - t1; 19055539Sluoqi t1 = t2; 19173911Sjhb } 192104306Sjmallett } 19373911Sjhb 194104306Sjmallett // reset current_callback 19555539Sluoqi osthread->remove_interrupt_callback(this); 19655539Sluoqi 19755539Sluoqi return status; 19855539Sluoqi} 199172836Sjulian 20055539Sluoqivoid OSThread::Sync_Interrupt_Callback::leave_callback() { 20173911Sjhb if (!_sync->owned_by_self()) { 202104306Sjmallett // notify requesting thread 203104306Sjmallett MutexLockerEx ml(_sync, Mutex::_no_safepoint_check_flag); 204173004Sjulian _is_done = true; 20555539Sluoqi _sync->notify_all(); 20673911Sjhb } else { 20755539Sluoqi // Current thread is interrupted while it is holding the _sync lock, trying 208173004Sjulian // to grab it again will deadlock. The requester will timeout anyway, 209173004Sjulian // so just return. 210173004Sjulian _is_done = true; 211173004Sjulian } 212173004Sjulian} 213173004Sjulian 214173004Sjulian// copied from synchronizer.cpp 215173004Sjulian 216173004Sjulianvoid OSThread::handle_spinlock_contention(int tries) { 217173004Sjulian if (NoYieldsInMicrolock) return; 218173004Sjulian 219173004Sjulian if (tries > 10) { 220173004Sjulian os::yield_all(tries); // Yield to threads of any priority 221173004Sjulian } else if (tries > 5) { 222173004Sjulian os::yield(); // Yield to threads of same or higher priority 223173004Sjulian } 224173004Sjulian} 225173004Sjulian