Java Unsafe-park操作

park/unpark操作

这两个操作通常配合在一起使用,park操作用于阻塞当前线程,unpark用于使阻塞在park操作代码处的线程退出阻塞。

 

park操作

该方法是一个native方法:

public native void park(boolean isAbsolute, long time);

该方法实现unsafe.cpp\hotspot\src\share\vm\prims目录下。

UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time))

  UnsafeWrapper("Unsafe_Park");

#ifndef USDT2

  HS_DTRACE_PROBE3(hotspot, thread__park__begin, thread->parker(), (int) isAbsolute, time);

#else /* USDT2 */

   HOTSPOT_THREAD_PARK_BEGIN(

                             (uintptr_t) thread->parker(), (int) isAbsolute, time);

#endif /* USDT2 */

  JavaThreadParkedState jtps(thread, time != 0);

  thread->parker()->park(isAbsolute != 0, time);

#ifndef USDT2

  HS_DTRACE_PROBE1(hotspot, thread__park__end, thread->parker());

#else /* USDT2 */

  HOTSPOT_THREAD_PARK_END(

                          (uintptr_t) thread->parker());

#endif /* USDT2 */

UNSAFE_END

以上代码需要展开来才能看得懂,展开后代码如下:

如果定义了USDT2

extern "C" {                                                        

  void JNICALL Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time) {                                      

    JavaThread* thread=JavaThread::thread_from_jni_environment(env);

    ThreadInVMfromNative __tiv(thread);

 

    /* do nothing */

 

    HandleMarkCleaner __hm(thread);                                   

    Thread* THREAD = thread;

 

    /* begin of body */

 

    /*nothing, for the present*/;

 

    ;

    JavaThreadParkedState jtps(thread, time != 0);

    thread->parker()->park(isAbsolute != 0, time);

    ;

  }

}

 

如果没有定义USDT2

这里不展开USDT2宏没有定义的那段代码

 

其中主要的代码在:

thread->parker()->park(isAbsolute != 0, time);

 

这块代码实现在os_solaris.cpp,在\hotspot\src\os\solaris\vm目录下。

void Parker::park(bool isAbsolute, jlong time) {

 

  // Optional fast-path check:

  // Return immediately if a permit is available.

  if (_counter > 0) {

      _counter = 0 ;

      OrderAccess::fence();

      return ;

  }

 

  // Optional fast-exit: Check interrupt before trying to wait

  Thread* thread = Thread::current();

  assert(thread->is_Java_thread(), "Must be JavaThread");

  JavaThread *jt = (JavaThread *)thread;

  if (Thread::is_interrupted(thread, false)) {

    return;

  }

 

  // First, demultiplex/decode time arguments

  timespec absTime;

  if (time < 0 || (isAbsolute && time == 0) ) { // don't wait at all

    return;

  }

  if (time > 0) {

    // Warning: this code might be exposed to the old Solaris time

    // round-down bugs.  Grep "roundingFix" for details.

    unpackTime(&absTime, isAbsolute, time);

  }

 

  // Enter safepoint region

  // Beware of deadlocks such as 6317397.

  // The per-thread Parker:: _mutex is a classic leaf-lock.

  // In particular a thread must never block on the Threads_lock while

  // holding the Parker:: mutex.  If safepoints are pending both the

  // the ThreadBlockInVM() CTOR and DTOR may grab Threads_lock.

  ThreadBlockInVM tbivm(jt);

 

  // Don't wait if cannot get lock since interference arises from

  // unblocking.  Also. check interrupt before trying wait

  if (Thread::is_interrupted(thread, false) ||

      os::Solaris::mutex_trylock(_mutex) != 0) {

    return;

  }

 

  int status ;

 

  if (_counter > 0)  { // no wait needed

    _counter = 0;

    status = os::Solaris::mutex_unlock(_mutex);

    assert (status == 0, "invariant") ;

    OrderAccess::fence();

    return;

  }

 

#ifdef ASSERT

  // Don't catch signals while blocked; let the running threads have the signals.

  // (This allows a debugger to break into the running thread.)

  sigset_t oldsigs;

  sigset_t* allowdebug_blocked = os::Solaris::allowdebug_blocked_signals();

  thr_sigsetmask(SIG_BLOCK, allowdebug_blocked, &oldsigs);

#endif

 

  OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);

  jt->set_suspend_equivalent();

  // cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()

 

  // Do this the hard way by blocking ...

  // See http://monaco.sfbay/detail.jsf?cr=5094058.

  // TODO-FIXME: for Solaris SPARC set fprs.FEF=0 prior to parking.

  // Only for SPARC >= V8PlusA

#if defined(__sparc) && defined(COMPILER2)

  if (ClearFPUAtPark) { _mark_fpu_nosave() ; }

#endif

 

  if (time == 0) {

    status = os::Solaris::cond_wait (_cond, _mutex) ;

  } else {

    status = os::Solaris::cond_timedwait (_cond, _mutex, &absTime);

  }

  // Note that an untimed cond_wait() can sometimes return ETIME on older

  // versions of the Solaris.

  assert_status(status == 0 || status == EINTR ||

                status == ETIME || status == ETIMEDOUT,

                status, "cond_timedwait");

 

#ifdef ASSERT

  thr_sigsetmask(SIG_SETMASK, &oldsigs, NULL);

#endif

  _counter = 0 ;

  status = os::Solaris::mutex_unlock(_mutex);

  assert_status(status == 0, status, "mutex_unlock") ;

 

  // If externally suspended while waiting, re-suspend

  if (jt->handle_special_suspend_equivalent_condition()) {

    jt->java_suspend_self();

  }

  OrderAccess::fence();

}

 

猜你喜欢

转载自lobin.iteye.com/blog/2327661
今日推荐