头文件:
art/runtime/thread.h
art/runtime/thread-current-inl.h

源文件:art/runtime/thread.cc

重要数据结构

  • 结构体 tls_ptr_sized_values
    在thread.h中,定义了一个十分重要的tls_ptr_sizedvalues类型全局变量tlsPtr,里面记录了很多重要的数据。
struct PACKED(sizeof(void*)) tls_ptr_sized_values {
    // Every thread may have an associated JNI environment
    JNIEnvExt* jni_env;

    // Initialized to "this". On certain architectures (such as x86) reading off of Thread::Current
    // is easy but getting the address of Thread::Current is hard. This field can be read off of
    // Thread::Current to give the address.
    Thread* self;
}

方法

  • GetJniEnv
    定义与实现:art/runtime/thread.h
 534   // JNI methods
 535   JNIEnvExt* GetJniEnv() const {
 536     return tlsPtr_.jni_env;
 537   }

tlsPtr_.jni_env是在Thread的Init方法中赋值的。

  • CreateNativeThread (创建native线程)
    Thread* child_thread = new Thread(is_daemon);

通过jni被调用

art/runtime/native/java_lang_Thread.cc:61:  Thread::CreateNativeThread(env, java_thread, stack_size, daemon == JNI_TRUE);
art/openjdkjvm/OpenjdkJvm.cc:347:  art::Thread::CreateNativeThread(env, jthread, stack_size, daemon == JNI_TRUE);
  • Startup (创建TSD的键)
    实现方法位于:art/runtime/thread.cc
2212 void Thread::Startup() {
2213   CHECK(!is_started_);
2214   is_started_ = true;
2215   {
2216     // MutexLock to keep annotalysis happy.
2217     //
2218     // Note we use null for the thread because Thread::Current can
2219     // return garbage since (is_started_ == true) and
2220     // Thread::pthread_key_self_ is not yet initialized.
2221     // This was seen on glibc.
2222     MutexLock mu(nullptr, *Locks::thread_suspend_count_lock_);
2223     resume_cond_ = new ConditionVariable("Thread resumption condition variable",
2224                                          *Locks::thread_suspend_count_lock_);
2225   }
2226 
2227   // Allocate a TLS slot.
2228   CHECK_PTHREAD_CALL(pthread_key_create, (&Thread::pthread_key_self_, Thread::ThreadExitCallback),
2229                      "self key");
2230 
2231   // Double-check the TLS slot allocation.
2232   if (pthread_getspecific(pthread_key_self_) != nullptr) {
2233     LOG(FATAL) << "Newly-created pthread TLS slot is not nullptr";
2234   }
2235 }

被Runtime实例的Init方法调用,详见:http://xinyiworld.top/wordpress_it/?p=14578

代码解释

2228   CHECK_PTHREAD_CALL(pthread_key_create, (&Thread::pthread_key_self_, Thread::ThreadExitCallback),
2229                      "self key");

CHECK_PTHREAD_CALL宏定义在system/core/base/include/android-base/logging.h

325 // Perform the pthread function call(args), LOG(FATAL) on error.
326 #define CHECK_PTHREAD_CALL(call, args, what)                           \
327   do {                                                                 \
328     int rc = call args;                                                \
329     if (rc != 0) {                                                     \
330       errno = rc;                                                      \
331       ABORT_AFTER_LOG_FATAL                                            \
332       PLOG(FATAL) << #call << " failed for " << (what);                \
333     }                                                                  \
334   } while (false)

那么以上代码就等于是执行pthread_key_create(&Thread::pthread_key_self_, Thread::ThreadExitCallback)方法

  • Current(获取当前线程实例)

实现方法位于art/runtime/thread-current-inl.h

 30 inline Thread* Thread::Current() {
 31   // We rely on Thread::Current returning null for a detached thread, so it's not obvious
 32   // that we can replace this with a direct %fs access on x86.
 33   if (!is_started_) {
 34     return nullptr;
 35   } else {
 36 #ifdef ART_TARGET_ANDROID
 37     void* thread = __get_tls()[TLS_SLOT_ART_THREAD_SELF];
 38 #else
 39     void* thread = pthread_getspecific(Thread::pthread_key_self_);
 40 #endif
 41     return reinterpret_cast<Thread*>(thread);
 42   }
 43 }
  • Init

将线程实例与线程数据键关联

TLS_SLOT_ART_THREAD_SELF宏定义在bionic/libc/private/bionic_asm_tls.h:92:#define TLS_SLOT_ART_THREAD_SELF 7

 935 #ifdef ART_TARGET_ANDROID
 936   __get_tls()[TLS_SLOT_ART_THREAD_SELF] = this;
 937 #else
 938   CHECK_PTHREAD_CALL(pthread_setspecific, (Thread::pthread_key_self_, this), "attach self");
 939 #endif

__get_tls()为汇编方法,定义在bionic/libc/private/__get_tls.h中。

创建JNIEnvExt实例

1)
对tlsPtr_.jni_env进行了赋值tlsPtr_.jni_env = JNIEnvExt::Create(this, java_vm, &error_msg);
2)
Init方法会被 void* Thread::CreateCallback(void* arg) Thread* Thread::Attach(const char* thread_name, bool as_daemon, PeerAction peer_action) 方法所调用。
3)
JNIEnvExt类见 http://xinyiworld.top/wordpress_it/?p=14639

  • Attach
    创建返回一个与当前art关联的Thread实例

962 template <typename PeerAction>
 963 Thread* Thread::Attach(const char* thread_name, bool as_daemon, PeerAction peer_action) {
 964   Runtime* runtime = Runtime::Current();
...
        //创建Thread实例(注意这里并不是真的创建了一个线程,而是创建了一个类,用于封装描述当前线程而已!!!!)
 981       self = new Thread(as_daemon);
 982       bool init_success = self->Init(runtime->GetThreadList(), runtime->GetJavaVM());

 996   // Run the action that is acting on the peer.
 997   if (!peer_action(self)) {
 998     runtime->GetThreadList()->Unregister(self);
 999     // Unregister deletes self, no need to do this here.
1000     return nullptr;
1001   }
...
1018   return self;
1019 }

1021 Thread* Thread::Attach(const char* thread_name,
1022                        bool as_daemon,
1023                        jobject thread_group,
1024                        bool create_peer) {
        //匿名函数
1025   auto create_peer_action = [&](Thread* self) {
1026     // If we're the main thread, ClassLinker won't be created until after we're attached,
1027     // so that thread needs a two-stage attach. Regular threads don't need this hack.
1028     // In the compiler, all threads need this hack, because no-one's going to be getting
1029     // a native peer!
1030     if (create_peer) {
1031       self->CreatePeer(thread_name, as_daemon, thread_group);
1032       if (self->IsExceptionPending()) {
1033         // We cannot keep the exception around, as we're deleting self. Try to be helpful and log
1034         // it.
1035         {
1036           ScopedObjectAccess soa(self);
1037           LOG(ERROR) << "Exception creating thread peer:";
1038           LOG(ERROR) << self->GetException()->Dump();
1039           self->ClearException();
1040         }
1041         return false;
1042       }
1043     } else {
1044       // These aren't necessary, but they improve diagnostics for unit tests & command-line tools.
1045       if (thread_name != nullptr) {
1046         self->tlsPtr_.name->assign(thread_name);
1047         ::art::SetThreadName(thread_name);
1048       } else if (self->GetJniEnv()->IsCheckJniEnabled()) {
1049         LOG(WARNING) << *Thread::Current() << " attached without supplying a name";
1050       }
1051     }
1052     return true;
1053   };
1054   return Attach(thread_name, as_daemon, create_peer_action);
1055 }

http://xinyiworld.top/wordpress_it/?p=14578,Attach方法会被Runtime的Init方法调用。


0 条评论

发表回复

您的电子邮箱地址不会被公开。