| 72 | } |
| 73 | |
| 74 | void* thread_getspecific(thread_key_t key) { |
| 75 | auto tls = (thread_local_storage*) (((partial_thread*) CURRENT)->tls); |
| 76 | if (!tls) { |
| 77 | return nullptr; |
| 78 | } |
| 79 | thread_key_data* data; |
| 80 | if (key < THREAD_KEY_2NDLEVEL_SIZE) |
| 81 | /* Special case access to the first 2nd-level block. This is the usual case. */ |
| 82 | data = &tls->specific_1stblock[key]; |
| 83 | else { |
| 84 | if (key >= THREAD_KEYS_MAX) |
| 85 | return nullptr; |
| 86 | uint64_t idx1st = key / THREAD_KEY_2NDLEVEL_SIZE; |
| 87 | uint64_t idx2nd = key % THREAD_KEY_2NDLEVEL_SIZE; |
| 88 | thread_key_data* level2 = tls->specific[idx1st]; |
| 89 | if (level2 == nullptr) |
| 90 | /* Not allocated, therefore no data. */ |
| 91 | return nullptr; |
| 92 | data = &level2[idx2nd]; |
| 93 | } |
| 94 | // Check seq against the global thread_keys |
| 95 | void* result = data->data; |
| 96 | if (result != nullptr) { |
| 97 | if (data->seq != thread_keys[key].seq) |
| 98 | result = data->data = nullptr; |
| 99 | } |
| 100 | return result; |
| 101 | } |
| 102 | |
| 103 | int thread_setspecific(thread_key_t key, const void* value) { |
| 104 | if (key >= THREAD_KEYS_MAX) |
no outgoing calls