// Deletes a pthread_key_t. note that the standard mandates that this does // not call the destructors for non-NULL key values. Instead, it is the // responsibility of the caller to properly dispose of the corresponding data // and resources, using any means it finds suitable. int pthread_key_delete(pthread_key_t key) { ScopedTlsMapAccess tls_map; if (!IsValidUserKey(key) || !tls_map.IsInUse(key)) { return EINVAL; } // Clear value in all threads. pthread_mutex_lock(&g_thread_list_lock); for (pthread_internal_t* t = g_thread_list; t != NULL; t = t->next) { // Skip zombie threads. They don't have a valid TLS area any more. // Similarly, it is possible to have t->tls == NULL for threads that // were just recently created through pthread_create() but whose // startup trampoline (__pthread_start) hasn't been run yet by the // scheduler. t->tls will also be NULL after a thread's stack has been // unmapped but before the ongoing pthread_join() is finished. if (t->tid == 0 || t->tls == NULL) { continue; } t->tls[key] = NULL; } tls_map.DeleteKey(key); pthread_mutex_unlock(&g_thread_list_lock); return 0; }
// Deletes a pthread_key_t. note that the standard mandates that this does // not call the destructors for non-NULL key values. Instead, it is the // responsibility of the caller to properly dispose of the corresponding data // and resources, using any means it finds suitable. int pthread_key_delete(pthread_key_t key) { ScopedTlsMapAccess tls_map; if (!IsValidUserKey(key) || !tls_map.IsInUse(key)) { return EINVAL; } // Clear value in all threads. pthread_mutex_lock(&gThreadListLock); for (pthread_internal_t* t = gThreadList; t != NULL; t = t->next) { // Avoid zombie threads with a negative 'join_count'. These are really // already dead and don't have a TLS area anymore. // Similarly, it is possible to have t->tls == NULL for threads that // were just recently created through pthread_create() but whose // startup trampoline (__thread_entry) hasn't been run yet by the // scheduler. t->tls will also be NULL after it's stack has been // unmapped but before the ongoing pthread_join() is finished. // so check for this too. if (t->join_count < 0 || !t->tls) { continue; } t->tls[key] = NULL; } tls_map.DeleteKey(key); pthread_mutex_unlock(&gThreadListLock); return 0; }
int pthread_setspecific(pthread_key_t key, const void* ptr) { ScopedTlsMapAccess tls_map; if (!IsValidUserKey(key) || !tls_map.IsInUse(key)) { return EINVAL; } __get_tls()[key] = const_cast<void*>(ptr); return 0; }
int pthread_setspecific(pthread_key_t key, const void* ptr) { ScopedTlsMapAccess tls_map; if (!IsValidUserKey(key) || !tls_map.IsInUse(key)) { return EINVAL; } ((uint32_t *)__get_tls())[key] = (uint32_t)ptr; return 0; }
void* pthread_getspecific(pthread_key_t key) { if (!IsValidUserKey(key)) { return NULL; } // For performance reasons, we do not lock/unlock the global TLS map // to check that the key is properly allocated. If the key was not // allocated, the value read from the TLS should always be NULL // due to pthread_key_delete() clearing the values for all threads. return __get_tls()[key]; }
// Deletes a pthread_key_t. note that the standard mandates that this does // not call the destructors for non-NULL key values. Instead, it is the // responsibility of the caller to properly dispose of the corresponding data // and resources, using any means it finds suitable. int pthread_key_delete(pthread_key_t key) { ScopedTlsMapAccess tls_map; if (!IsValidUserKey(key) || !tls_map.IsInUse(key)) { return EINVAL; } // Clear value in all threads. pthread_mutex_lock(&g_thread_list_lock); for (pthread_internal_t* t = g_thread_list; t != NULL; t = t->next) { t->tls[key] = NULL; } tls_map.DeleteKey(key); pthread_mutex_unlock(&g_thread_list_lock); return 0; }