NOTE: Can't borrow_keytable in bthread_setspecific, otherwise following memory leak may occur: -> bthread_getspecific fails to borrow_keytable and returns NULL. -> bthread_setspecific succeeds to borrow_keytable and overwrites old data at the position with newly created data, the old data is leaked.
| 624 | // -> bthread_setspecific succeeds to borrow_keytable and overwrites old data |
| 625 | // at the position with newly created data, the old data is leaked. |
| 626 | int bthread_setspecific(bthread_key_t key, void* data) { |
| 627 | bthread::KeyTable* kt = bthread::tls_bls.keytable; |
| 628 | if (NULL == kt) { |
| 629 | kt = new (std::nothrow) bthread::KeyTable; |
| 630 | if (NULL == kt) { |
| 631 | return ENOMEM; |
| 632 | } |
| 633 | bthread::tls_bls.keytable = kt; |
| 634 | bthread::TaskGroup* const g = bthread::BAIDU_GET_VOLATILE_THREAD_LOCAL(tls_task_group); |
| 635 | if (g) { |
| 636 | g->current_task()->local_storage.keytable = kt; |
| 637 | } else { |
| 638 | // Only cleanup keytable created by pthread. |
| 639 | // keytable created by bthread will be deleted |
| 640 | // in `return_keytable' or `bthread_keytable_pool_destroy'. |
| 641 | if (!bthread::tls_ever_created_keytable) { |
| 642 | bthread::tls_ever_created_keytable = true; |
| 643 | CHECK_EQ(0, butil::thread_atexit(bthread::cleanup_pthread, kt)); |
| 644 | } |
| 645 | } |
| 646 | } |
| 647 | return kt->set_data(key, data); |
| 648 | } |
| 649 | |
| 650 | void* bthread_getspecific(bthread_key_t key) { |
| 651 | bthread::KeyTable* kt = bthread::tls_bls.keytable; |