(转)ART学习笔记Thread SuspendAll部分

昨天碰到了一个Gc 时Suspend  All 超时导致的Runtime abort问题。

顺带就研究了下Suspend的机制以及超时检查的机制。


第一部分,suspend机制:


在进程被signal 3或者GC或者debugger尝试attach,就会suspend,那么suspend是如何实现的呢?

首先看一个Thread的 dump

  1. ”android.fg” prio=5 tid=19 Native  
  2.   | group=”“ sCount=1 dsCount=0 obj=0x12e5b740 self=0xb482f000  
  3.   | sysTid=590 nice=0 cgrp=default sched=0/0 handle=0xb4926d80  
  4.   | state=S schedstat=( 0 0 0 ) utm=59 stm=63 core=0 HZ=100  
  5.   | stack=0xa39f2000-0xa39f4000 stackSize=1036KB  
  6.   | held mutexes=  
  7.   native: #00 pc 000133cc  /system/lib/libc.so (syscall+28)  
  8.   native: #01 pc 000a99eb  /system/lib/libart.so (art::ConditionVariable::Wait(art::Thread*)+82)  
  9.   native: #02 pc 0027c8a5  /system/lib/libart.so (art::GoToRunnable(art::Thread*)+756)  
  10.   native: #03 pc 00087679  /system/lib/libart.so (art::JniMethodEnd(unsigned int, art::Thread*)+8)  
  11.   native: #04 pc 000b39d5  /data/dalvik-cache/arm/system@framework@boot.oat (Java_android_os_MessageQueue_nativePollOnce__JI+112)  
  12.   at android.os.MessageQueue.nativePollOnce(Native method)  
  13.   at android.os.MessageQueue.next(MessageQueue.java:143)  
  14.   at android.os.Looper.loop(Looper.java:122)  
  15.   at android.os.HandlerThread.run(HandlerThread.java:61)  
  16.   at com.android.server.ServiceThread.run(ServiceThread.java:46)  
"android.fg" prio=5 tid=19 Native
  | group="" sCount=1 dsCount=0 obj=0x12e5b740 self=0xb482f000
  | sysTid=590 nice=0 cgrp=default sched=0/0 handle=0xb4926d80
  | state=S schedstat=( 0 0 0 ) utm=59 stm=63 core=0 HZ=100
  | stack=0xa39f2000-0xa39f4000 stackSize=1036KB
  | held mutexes=
  native: #00 pc 000133cc  /system/lib/libc.so (syscall+28)
  native: #01 pc 000a99eb  /system/lib/libart.so (art::ConditionVariable::Wait(art::Thread*)+82)
  native: #02 pc 0027c8a5  /system/lib/libart.so (art::GoToRunnable(art::Thread*)+756)
  native: #03 pc 00087679  /system/lib/libart.so (art::JniMethodEnd(unsigned int, art::Thread*)+8)
  native: #04 pc 000b39d5  /data/dalvik-cache/arm/system@framework@boot.oat (Java_android_os_MessageQueue_nativePollOnce__JI+112)
  at android.os.MessageQueue.nativePollOnce(Native method)
  at android.os.MessageQueue.next(MessageQueue.java:143)
  at android.os.Looper.loop(Looper.java:122)
  at android.os.HandlerThread.run(HandlerThread.java:61)
  at com.android.server.ServiceThread.run(ServiceThread.java:46)

这个线程在Jni方法调用返回,想从native状态切换为Runnable状态时,检测到当前线程的suspend flag在位,于是进入conditionwait等待唤醒。


ART线程通过TransitionFreomSuspendToRunnable以及TransitionFromRunnableToSuspended两个函数来完成Runable到suspend或其他状态的转换。

而线程的常见状态有如下多种:

  1. enum ThreadState {  
  2.   //                                   Thread.State   JDWP state  
  3.   kTerminated = 66,                 // TERMINATED     TS_ZOMBIE    Thread.run has returned, but Thread* still around  
  4.   kRunnable,                        // RUNNABLE       TS_RUNNING   runnable  
  5.   kTimedWaiting,                    // TIMED_WAITING  TS_WAIT      in Object.wait() with a timeout  
  6.   kSleeping,                        // TIMED_WAITING  TS_SLEEPING  in Thread.sleep()  
  7.   kBlocked,                         // BLOCKED        TS_MONITOR   blocked on a monitor  
  8.   kWaiting,                         // WAITING        TS_WAIT      in Object.wait()  
  9.   kWaitingForGcToComplete,          // WAITING        TS_WAIT      blocked waiting for GC  
  10.   kWaitingForCheckPointsToRun,      // WAITING        TS_WAIT      GC waiting for checkpoints to run  
  11.   kWaitingPerformingGc,             // WAITING        TS_WAIT      performing GC  
  12.   kWaitingForDebuggerSend,          // WAITING        TS_WAIT      blocked waiting for events to be sent  
  13.   kWaitingForDebuggerToAttach,      // WAITING        TS_WAIT      blocked waiting for debugger to attach  
  14.   kWaitingInMainDebuggerLoop,       // WAITING        TS_WAIT      blocking/reading/processing debugger events  
  15.   kWaitingForDebuggerSuspension,    // WAITING        TS_WAIT      waiting for debugger suspend all  
  16.   kWaitingForJniOnLoad,             // WAITING        TS_WAIT      waiting for execution of dlopen and JNI on load code  
  17.   kWaitingForSignalCatcherOutput,   // WAITING        TS_WAIT      waiting for signal catcher IO to complete  
  18.   kWaitingInMainSignalCatcherLoop,  // WAITING        TS_WAIT      blocking/reading/processing signals  
  19.   kWaitingForDeoptimization,        // WAITING        TS_WAIT      waiting for deoptimization suspend all  
  20.   kWaitingForMethodTracingStart,    // WAITING        TS_WAIT      waiting for method tracing to start  
  21.   kStarting,                        // NEW            TS_WAIT      native thread started, not yet ready to run managed code  
  22.   kNative,                          // RUNNABLE       TS_RUNNING   running in a JNI native method  
  23.   kSuspended,                       // RUNNABLE       TS_RUNNING   suspended by GC or debugger  
  24. };  
enum ThreadState {
  //                                   Thread.State   JDWP state
  kTerminated = 66,                 // TERMINATED     TS_ZOMBIE    Thread.run has returned, but Thread* still around
  kRunnable,                        // RUNNABLE       TS_RUNNING   runnable
  kTimedWaiting,                    // TIMED_WAITING  TS_WAIT      in Object.wait() with a timeout
  kSleeping,                        // TIMED_WAITING  TS_SLEEPING  in Thread.sleep()
  kBlocked,                         // BLOCKED        TS_MONITOR   blocked on a monitor
  kWaiting,                         // WAITING        TS_WAIT      in Object.wait()
  kWaitingForGcToComplete,          // WAITING        TS_WAIT      blocked waiting for GC
  kWaitingForCheckPointsToRun,      // WAITING        TS_WAIT      GC waiting for checkpoints to run
  kWaitingPerformingGc,             // WAITING        TS_WAIT      performing GC
  kWaitingForDebuggerSend,          // WAITING        TS_WAIT      blocked waiting for events to be sent
  kWaitingForDebuggerToAttach,      // WAITING        TS_WAIT      blocked waiting for debugger to attach
  kWaitingInMainDebuggerLoop,       // WAITING        TS_WAIT      blocking/reading/processing debugger events
  kWaitingForDebuggerSuspension,    // WAITING        TS_WAIT      waiting for debugger suspend all
  kWaitingForJniOnLoad,             // WAITING        TS_WAIT      waiting for execution of dlopen and JNI on load code
  kWaitingForSignalCatcherOutput,   // WAITING        TS_WAIT      waiting for signal catcher IO to complete
  kWaitingInMainSignalCatcherLoop,  // WAITING        TS_WAIT      blocking/reading/processing signals
  kWaitingForDeoptimization,        // WAITING        TS_WAIT      waiting for deoptimization suspend all
  kWaitingForMethodTracingStart,    // WAITING        TS_WAIT      waiting for method tracing to start
  kStarting,                        // NEW            TS_WAIT      native thread started, not yet ready to run managed code
  kNative,                          // RUNNABLE       TS_RUNNING   running in a JNI native method
  kSuspended,                       // RUNNABLE       TS_RUNNING   suspended by GC or debugger
};

在线程切换Suspend状态时,首先是需要将suspendcount++,并将标志KSuspendRequest置位。

这样,在很多场景(几乎各个跳转场景,目前我还没弄清出解释器的执行方式)下在checkSuspend的时候,就会block住:

  1. static inline void CheckSuspend(Thread* thread) {  
  2.   for (;;) {  
  3.     if (thread->ReadFlag(kCheckpointRequest)) {  
  4.       thread->RunCheckpointFunction();  
  5.     } else if (thread->ReadFlag(kSuspendRequest)) {  
  6.       thread->FullSuspendCheck();  
  7.     } else {  
  8.       break;  
  9.     }  
  10.   }  
  11. }  
static inline void CheckSuspend(Thread* thread) {
  for (;;) {
    if (thread->ReadFlag(kCheckpointRequest)) {
      thread->RunCheckpointFunction();
    } else if (thread->ReadFlag(kSuspendRequest)) {
      thread->FullSuspendCheck();
    } else {
      break;
    }
  }
}

  1. void Thread::FullSuspendCheck() {  
  2.   VLOG(threads) << this << “ self-suspending”;  
  3.   ATRACE_BEGIN(”Full suspend check”);  
  4.   // Make thread appear suspended to other threads, release mutator_lock_.  
  5.   TransitionFromRunnableToSuspended(kSuspended);  
  6.   // Transition back to runnable noting requests to suspend, re-acquire share on mutator_lock_.  
  7.   TransitionFromSuspendedToRunnable();  
  8.   ATRACE_END();  
  9.   VLOG(threads) << this << “ self-reviving”;  
  10. }  
void Thread::FullSuspendCheck() {
  VLOG(threads) << this << " self-suspending";
  ATRACE_BEGIN("Full suspend check");
  // Make thread appear suspended to other threads, release mutator_lock_.
  TransitionFromRunnableToSuspended(kSuspended);
  // Transition back to runnable noting requests to suspend, re-acquire share on mutator_lock_.
  TransitionFromSuspendedToRunnable();
  ATRACE_END();
  VLOG(threads) << this << " self-reviving";
}


或者在JNI函数退出的时候,尝试从Native状态切成Runnable的时候,也会去做TransitionFreomSuspendToRunnable

在JNI函数进入的时候,从Runnalbe状态切到Native的时候,也会去做TransitionFromRunnableToSuspended

  1. extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self) {  
  2.   GoToRunnable(self);  
  3.   PopLocalReferences(saved_local_ref_cookie, self);  
  4. }  
extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self) {
  GoToRunnable(self);
  PopLocalReferences(saved_local_ref_cookie, self);
}


  1. static void GoToRunnable(Thread* self) NO_THREAD_SAFETY_ANALYSIS {  
  2.   mirror::ArtMethod* native_method = self->GetManagedStack()->GetTopQuickFrame()->AsMirrorPtr();  
  3.   bool is_fast = native_method->IsFastNative();  
  4.   if (!is_fast) {  
  5.     self->TransitionFromSuspendedToRunnable();  
  6.   } else if (UNLIKELY(self->TestAllFlags())) {  
  7.     // In fast JNI mode we never transitioned out of runnable. Perform a suspend check if there  
  8.     // is a flag raised.  
  9.     DCHECK(Locks::mutator_lock_->IsSharedHeld(self));  
  10.     CheckSuspend(self);  
  11.   }  
  12. }  
static void GoToRunnable(Thread* self) NO_THREAD_SAFETY_ANALYSIS {
  mirror::ArtMethod* native_method = self->GetManagedStack()->GetTopQuickFrame()->AsMirrorPtr();
  bool is_fast = native_method->IsFastNative();
  if (!is_fast) {
    self->TransitionFromSuspendedToRunnable();
  } else if (UNLIKELY(self->TestAllFlags())) {
    // In fast JNI mode we never transitioned out of runnable. Perform a suspend check if there
    // is a flag raised.
    DCHECK(Locks::mutator_lock_->IsSharedHeld(self));
    CheckSuspend(self);
  }
}
  1.   


那么下面就去看看这个函数的实现:

  1. inline void Thread::TransitionFromRunnableToSuspended(ThreadState new_state) {  
  2.   AssertThreadSuspensionIsAllowable();  
  3.   DCHECK_NE(new_state, kRunnable);  
  4.   DCHECK_EQ(this, Thread::Current());  
  5.   // Change to non-runnable state, thereby appearing suspended to the system.  
  6.   DCHECK_EQ(GetState(), kRunnable);  
  7.   union StateAndFlags old_state_and_flags;  
  8.   union StateAndFlags new_state_and_flags;  
  9.   while (true) {  
  10.     old_state_and_flags.as_int = tls32_.state_and_flags.as_int;  
  11.     if (UNLIKELY((old_state_and_flags.as_struct.flags & kCheckpointRequest) != 0)) {  
  12.       RunCheckpointFunction();  
  13.       continue;  
  14.     }  
  15.     // Change the state but keep the current flags (kCheckpointRequest is clear).  
  16.     DCHECK_EQ((old_state_and_flags.as_struct.flags & kCheckpointRequest), 0);  
  17.     new_state_and_flags.as_struct.flags = old_state_and_flags.as_struct.flags;  
  18.     new_state_and_flags.as_struct.state = new_state;  
  19.   
  20.     // CAS the value without a memory ordering as that is given by the lock release below.  
  21.     bool done =  
  22.         tls32_.state_and_flags.as_atomic_int.CompareExchangeWeakRelaxed(old_state_and_flags.as_int,  
  23.                                                                         new_state_and_flags.as_int);  
  24.     if (LIKELY(done)) {  
  25.       break;  
  26.     }  
  27.   }  
  28.   // Release share on mutator_lock_.  
  29.   Locks::mutator_lock_->SharedUnlock(this);  
  30. }  
inline void Thread::TransitionFromRunnableToSuspended(ThreadState new_state) {
  AssertThreadSuspensionIsAllowable();
  DCHECK_NE(new_state, kRunnable);
  DCHECK_EQ(this, Thread::Current());
  // Change to non-runnable state, thereby appearing suspended to the system.
  DCHECK_EQ(GetState(), kRunnable);
  union StateAndFlags old_state_and_flags;
  union StateAndFlags new_state_and_flags;
  while (true) {
    old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
    if (UNLIKELY((old_state_and_flags.as_struct.flags & kCheckpointRequest) != 0)) {
      RunCheckpointFunction();
      continue;
    }
    // Change the state but keep the current flags (kCheckpointRequest is clear).
    DCHECK_EQ((old_state_and_flags.as_struct.flags & kCheckpointRequest), 0);
    new_state_and_flags.as_struct.flags = old_state_and_flags.as_struct.flags;
    new_state_and_flags.as_struct.state = new_state;

    // CAS the value without a memory ordering as that is given by the lock release below.
    bool done =
        tls32_.state_and_flags.as_atomic_int.CompareExchangeWeakRelaxed(old_state_and_flags.as_int,
                                                                        new_state_and_flags.as_int);
    if (LIKELY(done)) {
      break;
    }
  }
  // Release share on mutator_lock_.
  Locks::mutator_lock_->SharedUnlock(this);
}
可以切换到suspend状态比较简单,置位+放锁mutator,这个放锁非常重要,是超时检测 机制的核心状态,后面会详细讲。

从suspend状态切回runnable:

  1. inline ThreadState Thread::TransitionFromSuspendedToRunnable() {  
  2.   bool done = false;  
  3.   union StateAndFlags old_state_and_flags;  
  4.   old_state_and_flags.as_int = tls32_.state_and_flags.as_int;  
  5.   int16_t old_state = old_state_and_flags.as_struct.state;  
  6.   DCHECK_NE(static_cast<ThreadState>(old_state), kRunnable);  
  7.   do {  
  8.     Locks::mutator_lock_->AssertNotHeld(this);  // Otherwise we starve GC..  
  9.     old_state_and_flags.as_int = tls32_.state_and_flags.as_int;  
  10.     DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);  
  11.     if (UNLIKELY((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0)) {  
  12.       // Wait while our suspend count is non-zero.  
  13.       MutexLock mu(this, *Locks::thread_suspend_count_lock_);  
  14.       old_state_and_flags.as_int = tls32_.state_and_flags.as_int;  
  15.       DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);  
  16.       while ((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0) {// 当未被唤醒时,KsuspendRequst始终不为0,因此,进入conditionwait,也就是上面发的dump那样  
  17.         // Re-check when Thread::resume_cond_ is notified.  
  18.         Thread::resume_cond_->Wait(this);  
  19.         old_state_and_flags.as_int = tls32_.state_and_flags.as_int;  
  20.         DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);  
  21.       }  
  22.       DCHECK_EQ(GetSuspendCount(), 0);  
  23.     }  
  24.     // Re-acquire shared mutator_lock_ access.  
  25.     Locks::mutator_lock_->SharedLock(this);  
  26.     // Atomically change from suspended to runnable if no suspend request pending.  
  27.     old_state_and_flags.as_int = tls32_.state_and_flags.as_int;  
  28.     DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);  
  29.     if (LIKELY((old_state_and_flags.as_struct.flags & kSuspendRequest) == 0)) {  
  30.       union StateAndFlags new_state_and_flags;  
  31.       new_state_and_flags.as_int = old_state_and_flags.as_int;  
  32.       new_state_and_flags.as_struct.state = kRunnable;  
  33.       // CAS the value without a memory ordering as that is given by the lock acquisition above.  
  34.       done =  
  35.           tls32_.state_and_flags.as_atomic_int.CompareExchangeWeakRelaxed(old_state_and_flags.as_int,  
  36.                                                                           new_state_and_flags.as_int);  
  37.     }  
  38.     if (UNLIKELY(!done)) {  
  39.       // Failed to transition to Runnable. Release shared mutator_lock_ access and try again.  
  40.       Locks::mutator_lock_->SharedUnlock(this);  
  41.     } else {  
  42.       return static_cast<ThreadState>(old_state);  
  43.     }  
  44.   } while (true);  
inline ThreadState Thread::TransitionFromSuspendedToRunnable() {
  bool done = false;
  union StateAndFlags old_state_and_flags;
  old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
  int16_t old_state = old_state_and_flags.as_struct.state;
  DCHECK_NE(static_cast<ThreadState>(old_state), kRunnable);
  do {
    Locks::mutator_lock_->AssertNotHeld(this);  // Otherwise we starve GC..
    old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
    DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
    if (UNLIKELY((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0)) {
      // Wait while our suspend count is non-zero.
      MutexLock mu(this, *Locks::thread_suspend_count_lock_);
      old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
      DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
      while ((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0) {// 当未被唤醒时,KsuspendRequst始终不为0,因此,进入conditionwait,也就是上面发的dump那样
        // Re-check when Thread::resume_cond_ is notified.
        Thread::resume_cond_->Wait(this);
        old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
        DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
      }
      DCHECK_EQ(GetSuspendCount(), 0);
    }
    // Re-acquire shared mutator_lock_ access.
    Locks::mutator_lock_->SharedLock(this);
    // Atomically change from suspended to runnable if no suspend request pending.
    old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
    DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
    if (LIKELY((old_state_and_flags.as_struct.flags & kSuspendRequest) == 0)) {
      union StateAndFlags new_state_and_flags;
      new_state_and_flags.as_int = old_state_and_flags.as_int;
      new_state_and_flags.as_struct.state = kRunnable;
      // CAS the value without a memory ordering as that is given by the lock acquisition above.
      done =
          tls32_.state_and_flags.as_atomic_int.CompareExchangeWeakRelaxed(old_state_and_flags.as_int,
                                                                          new_state_and_flags.as_int);
    }
    if (UNLIKELY(!done)) {
      // Failed to transition to Runnable. Release shared mutator_lock_ access and try again.
      Locks::mutator_lock_->SharedUnlock(this);
    } else {
      return static_cast<ThreadState>(old_state);
    }
  } while (true);

首先去检测,当ksuspendrequst在位时,进入condition wait等待唤醒,唤醒完毕后,那mutator lock,并改变当前的状态,注意这里使用的是原子操作。

其实我们可以看到,suspend的核心就是在KsuspendRequset标志位在位的时候,线程会进入condition wait中等待唤醒,于是乎就suspend停了下来。

那么问题来了,如何检测所有的进程已经suspend好了以便我执行下面的操作了?


第二部分,suspend超时检测机制。

上面有提到,在进入suspend和runnalbe状态的时候,跟随着对mutatorlock的lock和unlock,mutatorlock是线程在运行的时候需要拿的锁,很多函数都声明了需要这个lock的保护,那么我们可以根据mutatorlock的状态来检测是否还有人处于runnalbe状态,art的实现如下:

  1.   // Block on the mutator lock until all Runnable threads release their share of access.  
  2. #if HAVE_TIMED_RWLOCK  
  3.   // Timeout if we wait more than 30 seconds.  
  4.   if (!Locks::mutator_lock_->ExclusiveLockWithTimeout(self, 30 * 1000, 0)) {  
  5.       
  6.         UnsafeLogFatalForThreadSuspendAllTimeout();  
  7.   }  
  8. #else  
  9.   Locks::mutator_lock_->ExclusiveLock(self);  
  10. #endif  
  // Block on the mutator lock until all Runnable threads release their share of access.




if HAVE_TIMED_RWLOCK

// Timeout if we wait more than 30 seconds.
if (!Locks::mutator_lock_->ExclusiveLockWithTimeout(self, 30 * 1000, 0)) {

    UnsafeLogFatalForThreadSuspendAllTimeout();

}

else

Locks::mutator_lock_->ExclusiveLock(self);

endif


尝试去获取mutator_lock,并设置了超时时间为30s,具体的实现就是一个futex_wait,这里就不说了。

其实在dumplog中我们只要找到状态为runnalbe的线程,就是导致超时的原因了。

顺带在说下为什么在synchronized中等待的(blocked)线程并不会超时:

synchronized的实现就就是Monitor,这个和dvm中的实现比较类似,都是基于thin和fat lock的。

当线程进入synchronized等待现在锁的持有者执行完毕的时候,会将自己的状态从runnable切换成block,同时创建了ScopedThreadStateChange对象,而对象的构造函数中调用了上面的方法:

  1. class ScopedThreadStateChange {  
  2.  public:  
  3.   ScopedThreadStateChange(Thread* self, ThreadState new_thread_state)  
  4.       LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_) ALWAYS_INLINE  
  5.       : self_(self), thread_state_(new_thread_state), expected_has_no_thread_(false) {  
  6.     if (UNLIKELY(self_ == NULL)) {  
  7.       // Value chosen arbitrarily and won’t be used in the destructor since thread_ == NULL.  
  8.       old_thread_state_ = kTerminated;  
  9.       Runtime* runtime = Runtime::Current();  
  10.       CHECK(runtime == NULL || !runtime->IsStarted() || runtime->IsShuttingDown(self_));  
  11.     } else {  
  12.       DCHECK_EQ(self, Thread::Current());  
  13.       // Read state without locks, ok as state is effectively thread local and we’re not interested  
  14.       // in the suspend count (this will be handled in the runnable transitions).  
  15.       old_thread_state_ = self->GetState();  
  16.       if (old_thread_state_ != new_thread_state) {  
  17.         if (new_thread_state == kRunnable) {  
  18.           self_->TransitionFromSuspendedToRunnable();  
  19.         } else if (old_thread_state_ == kRunnable) {  
  20.           self_->TransitionFromRunnableToSuspended(new_thread_state);  
  21.         } else {  
  22.           // A suspended transition to another effectively suspended transition, ok to use Unsafe.  
  23.           self_->SetState(new_thread_state);  
  24.         }  
  25.       }  
  26.     }  
  27.   }  
class ScopedThreadStateChange {
 public:
  ScopedThreadStateChange(Thread* self, ThreadState new_thread_state)
      LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_) ALWAYS_INLINE
      : self_(self), thread_state_(new_thread_state), expected_has_no_thread_(false) {
    if (UNLIKELY(self_ == NULL)) {
      // Value chosen arbitrarily and won't be used in the destructor since thread_ == NULL.
      old_thread_state_ = kTerminated;
      Runtime* runtime = Runtime::Current();
      CHECK(runtime == NULL || !runtime->IsStarted() || runtime->IsShuttingDown(self_));
    } else {
      DCHECK_EQ(self, Thread::Current());
      // Read state without locks, ok as state is effectively thread local and we're not interested
      // in the suspend count (this will be handled in the runnable transitions).
      old_thread_state_ = self->GetState();
      if (old_thread_state_ != new_thread_state) {
        if (new_thread_state == kRunnable) {
          self_->TransitionFromSuspendedToRunnable();
        } else if (old_thread_state_ == kRunnable) {
          self_->TransitionFromRunnableToSuspended(new_thread_state);
        } else {
          // A suspended transition to another effectively suspended transition, ok to use Unsafe.
          self_->SetState(new_thread_state);
        }
      }
    }
  }

所以,被block住的线程,也是放掉了mutator_lock的。

在我现在看来,mutatorlock就是线程是否在可执行状态的标志。

总结下,suspend就是将KsuspendRequest置位,在线程执行的某些位置会进行检查,从而完成其他状态到suspend的切换,同时unlock mutatorlock。

suspend的检查就是尝试在30s内获取mutatorlock,如果超时,那么证明还有线程还没有执行完毕当前的任务,则dump stack,并runtime abort。

好了,就到这里,备忘备忘,不过肯定有理解错误的,我很担心我猜测的checksuspend执行点的错误,后面碰到问题再看。











        </div>
            </div>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值