Add secondary counter in place of tls_nodelete flag
The tls_nodelete state should apply to load_group not
isolated soinfo. This actually also means that multiple
soinfos may have tls_counter on their dso_handles.
This change replaces TLS_NODELETE flag with secondary counter.
Note that access to the secondary counter (located inside soinfo)
is pretty expensive because it requires soinfo lookup by dso_handle
whereas dso_handle counter is much faster. This is why it is updated
only when dso_handle counter starts or hits 0.
Bug: http://b/80278285
Test: bionic-unit-tests --gtest_filter=dl*
Change-Id: I535583f6714e45fa2a7eaf7bb3126da20ee7cba9
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 0a931c6..12d3a78 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1937,7 +1937,7 @@
soinfo* si = find_containing_library(dso_handle);
if (si != nullptr) {
ProtectedDataGuard guard;
- si->set_tls_nodelete();
+ si->increment_ref_count();
} else {
async_safe_fatal(
"increment_dso_handle_reference_counter: Couldn't find soinfo by dso_handle=%p",
@@ -1960,11 +1960,7 @@
soinfo* si = find_containing_library(dso_handle);
if (si != nullptr) {
ProtectedDataGuard guard;
- si->unset_tls_nodelete();
- if (si->get_ref_count() == 0) {
- // Perform deferred unload - note that soinfo_unload_impl does not decrement ref_count
- soinfo_unload_impl(si);
- }
+ soinfo_unload(si);
} else {
async_safe_fatal(
"decrement_dso_handle_reference_counter: Couldn't find soinfo by dso_handle=%p",
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index 731e8f5..3191ac7 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -537,14 +537,6 @@
rtld_flags_ |= RTLD_NODELETE;
}
-void soinfo::set_tls_nodelete() {
- flags_ |= FLAG_TLS_NODELETE;
-}
-
-void soinfo::unset_tls_nodelete() {
- flags_ &= ~FLAG_TLS_NODELETE;
-}
-
const char* soinfo::get_realpath() const {
#if defined(__work_around_b_24465209__)
if (has_min_version(2)) {
@@ -660,8 +652,7 @@
bool soinfo::can_unload() const {
return !is_linked() ||
(
- (get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0 &&
- (flags_ & FLAG_TLS_NODELETE) == 0
+ (get_rtld_flags() & (RTLD_NODELETE | RTLD_GLOBAL)) == 0
);
}
diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h
index 6e1f005..09e5065 100644
--- a/linker/linker_soinfo.h
+++ b/linker/linker_soinfo.h
@@ -51,7 +51,7 @@
// when load group is crossing
// namespace boundary twice and second
// local group depends on the same libraries.
-#define FLAG_TLS_NODELETE 0x00000200 // This flag set when there is at least one
+#define FLAG_RESERVED 0x00000200 // This flag was set when there is at least one
// outstanding thread_local dtor
// registered with this soinfo. In such
// a case the actual unload is
@@ -260,8 +260,6 @@
void set_linker_flag();
void set_main_executable();
void set_nodelete();
- void set_tls_nodelete();
- void unset_tls_nodelete();
size_t increment_ref_count();
size_t decrement_ref_count();