// The first ELF TLS module has ID 1. Zero is reserved for the first word of // the DTV, a generation count. Unresolved weak symbols also use module ID 0. static constexpr size_t kTlsUninitializedModuleId = 0;
// A descriptor for a single ELF TLS module. struct TlsModule {
TlsSegment segment;
// Offset into the static TLS block or SIZE_MAX for a dynamic module.
size_t static_offset = SIZE_MAX;
// The generation in which this module was loaded. Dynamic TLS lookups use // this field to detect when a module has been unloaded.
size_t first_generation = kTlsGenerationNone;
// Used by the dynamic linker to track the associated soinfo* object. void* soinfo_ptr = nullptr;
};
// Signature of the callbacks that will be called after DTLS creation and // before DTLS destruction. typedefvoid (*dtls_listener_t)(void* dynamic_tls_begin, void* dynamic_tls_end);
// Signature of the thread-exit callbacks. typedefvoid (*thread_exit_cb_t)(void);
// Table of the ELF TLS modules. Either the dynamic linker or the static // initialization code prepares this table, and it's then used during thread // creation and for dynamic TLS lookups. struct TlsModules {
constexpr TlsModules() {}
// A pointer to the TLS generation counter in libc.so. The counter is // incremented each time an solib is loaded or unloaded.
_Atomic(size_t) generation = kTlsGenerationFirst;
_Atomic(size_t) *generation_libc_so = nullptr;
// Access to the TlsModule[] table requires taking this lock.
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
// Pointer to a block of TlsModule objects. The first module has ID 1 and // is stored at index 0 in this table.
size_t module_count = 0;
size_t static_module_count = 0;
TlsModule* module_table = nullptr;
// Callback to be invoked after a dynamic TLS allocation.
dtls_listener_t on_creation_cb = nullptr;
// Callback to be invoked before a dynamic TLS deallocation.
dtls_listener_t on_destruction_cb = nullptr;
// The first thread-exit callback; inlined to avoid allocation.
thread_exit_cb_t first_thread_exit_callback = nullptr;
// The additional callbacks, if any.
CallbackHolder* thread_exit_callback_tail_node = nullptr;
};
void __init_static_tls(void* static_tls);
// Dynamic Thread Vector. Each thread has a different DTV. For each module // (executable or solib), the DTV has a pointer to that module's TLS memory. The // DTV is initially empty and is allocated on-demand. It grows as more modules // are dlopen'ed. See https://www.akkadia.org/drepper/tls.pdf. // // The layout of the DTV is specified in various documents, but it is not part // of Bionic's public ABI. A compiler can't generate code to access it directly, // because it can't access libc's global generation counter. struct TlsDtv { // Number of elements in this object's modules field.
size_t count;
// A pointer to an older TlsDtv object that should be freed when the thread // exits. The objects aren't immediately freed because a DTV could be // reallocated by a signal handler that interrupted __tls_get_addr's fast // path.
TlsDtv* next;
// The DTV slot points at this field, which allows omitting an add instruction // on the fast path for a TLS lookup. The arm64 tlsdesc_resolver.S depends on // the layout of fields past this point.
size_t generation; void* modules[];
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.