void deallocate_tls()

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;
}