in thread/thread-key.cpp [155:209]
void deallocate_tls(void** tls_) {
size_t round = 0;
auto ptr = tls_ ? *tls_ : ((partial_thread*)CURRENT)->tls;
auto tls = (thread_local_storage*)ptr;
if (!tls) return; /* No key was ever created */
if (!tls->specific_used) goto free_tls; /* No specific was ever set */
do {
uint64_t idx = 0;
tls->specific_used = false;
for (auto level2 : tls->specific) {
if (level2 != nullptr) {
for (uint64_t inner = 0; inner < THREAD_KEY_2NDLEVEL_SIZE; ++inner, ++idx) {
void* data = level2[inner].data;
if (data == nullptr) {
continue;
}
/* Always clear the data. */
level2[inner].data = nullptr;
/* Make sure the data corresponds to a valid key. */
if (level2[inner].seq == thread_keys[idx].seq && thread_keys[idx].dtor != nullptr)
/* Call the user-provided destructor. */
thread_keys[idx].dtor(data);
}
} else {
idx += THREAD_KEY_1STLEVEL_SIZE;
}
}
if (!tls->specific_used) {
/* Usually no data has been modified,
* unless users have called thread_setspecific in the destructor */
goto free_key;
}
} /* We only repeat the process a fixed number of times. */
while (++round < THREAD_DESTRUCTOR_ITERATIONS);
/* Just clear the memory of the first block for reuse. */
memset(&tls->specific_1stblock, 0, sizeof(tls->specific_1stblock));
free_key:
/* Free the memory for the other blocks. */
for (uint64_t cnt = 1; cnt < THREAD_KEY_1STLEVEL_SIZE; ++cnt) {
thread_key_data* level2 = tls->specific[cnt];
if (level2 != nullptr) {
free(level2);
tls->specific[cnt] = nullptr;
}
}
tls->specific_used = false;
free_tls:
delete tls;
if (tls_)
*tls_ = nullptr;
}