int PREFIXED(setspecific) (tsd * key, void * value) { pthread_t self = pthread_self(); int hash_val = HASH(self); volatile tse * entry = (volatile tse *)MALLOC_CLEAR(sizeof (tse)); GC_ASSERT(self != INVALID_THREADID); if (0 == entry) return ENOMEM; pthread_mutex_lock(&(key -> lock)); /* Could easily check for an existing entry here. */ entry -> next = key -> hash[hash_val]; entry -> thread = self; entry -> value = value; GC_ASSERT(entry -> qtid == INVALID_QTID); /* There can only be one writer at a time, but this needs to be */ /* atomic with respect to concurrent readers. */ *(volatile tse **)(key -> hash + hash_val) = entry; pthread_mutex_unlock(&(key -> lock)); return 0; }
int PREFIXED(key_create) (tsd ** key_ptr, void (* destructor)(void *)) { int i; tsd * result = (tsd *)MALLOC_CLEAR(sizeof (tsd)); /* A quick alignment check, since we need atomic stores */ GC_ASSERT((unsigned long)(&invalid_tse.next) % sizeof(tse *) == 0); if (0 == result) return ENOMEM; pthread_mutex_init(&(result -> lock), NULL); for (i = 0; i < TS_CACHE_SIZE; ++i) { result -> cache[i] = &invalid_tse; } # ifdef GC_ASSERTIONS for (i = 0; i < TS_HASH_SIZE; ++i) { GC_ASSERT(result -> hash[i] == 0); } # endif *key_ptr = result; return 0; }
GC_INNER int GC_key_create_inner(tsd ** key_ptr) { int i; tsd * result = (tsd *)MALLOC_CLEAR(sizeof(tsd)); /* A quick alignment check, since we need atomic stores */ GC_ASSERT((word)(&invalid_tse.next) % sizeof(tse *) == 0); if (0 == result) return ENOMEM; pthread_mutex_init(&(result -> lock), NULL); for (i = 0; i < TS_CACHE_SIZE; ++i) { result -> cache[i] = (/* no const */ tse *)&invalid_tse; } # ifdef GC_ASSERTIONS for (i = 0; i < TS_HASH_SIZE; ++i) { GC_ASSERT(result -> hash[i].p == 0); } # endif *key_ptr = result; return 0; }
/* Called with the lock held. */ GC_INNER int GC_setspecific(tsd * key, void * value) { pthread_t self = pthread_self(); int hash_val = HASH(self); volatile tse * entry; GC_ASSERT(self != INVALID_THREADID); GC_dont_gc++; /* disable GC */ entry = (volatile tse *)MALLOC_CLEAR(sizeof(tse)); GC_dont_gc--; if (0 == entry) return ENOMEM; pthread_mutex_lock(&(key -> lock)); /* Could easily check for an existing entry here. */ entry -> next = key->hash[hash_val].p; entry -> thread = self; entry -> value = value; GC_ASSERT(entry -> qtid == INVALID_QTID); /* There can only be one writer at a time, but this needs to be */ /* atomic with respect to concurrent readers. */ AO_store_release(&key->hash[hash_val].ao, (AO_t)entry); pthread_mutex_unlock(&(key -> lock)); return 0; }