annotate src/os/solaris/vm/osThread_solaris.cpp @ 0:a61af66fc99e

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