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