头文件:
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 条评论