bool SIZE(libat_compare_exchange) (UTYPE *mptr, UTYPE *eptr, UTYPE newval, int smodel, int fmodel UNUSED) { if (maybe_specialcase_relaxed(smodel)) return atomic_compare_exchange_n (mptr, eptr, newval, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED); else if (maybe_specialcase_acqrel(smodel)) return atomic_compare_exchange_n (mptr, eptr, newval, false, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED); else return atomic_compare_exchange_n (mptr, eptr, newval, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED); }
static int atomic_hash_table_update_one_file(english_word *word){ uint64_t hashv=fnv_hash(word->str,word->len); uint64_t index=hashv%global_hash_table_size; //this next line results in a lot of cache misses //for obvious reasons if(!global_hash_table[index]){//word isn't in the hash table, add it uint8_t *mem=xmalloc(word->len); word->str=(char*)my_strcpy(mem,(uint8_t*)word->str,word->len); void *prev=global_hash_table[index]; int test=atomic_compare_exchange_n(global_hash_table+index,&prev,word); if(test){ //we added the word //this needs to be atomic to prevent two threads writing different //values to the same index of indices uint64_t old_indices_index=atomic_fetch_add(&indices_index,1); //this doesn't need to be atomic, since indices_index will never be //decremented, so no one else will change this hash_table_indices[old_indices_index]=index; goto end1; } //else, someone else changed the value of global_hash_table[index] before us } while(1){ do { //see if the value in the table is the same as our value //if so update the value already in the table if(string_compare(global_hash_table[index],word)){ //atomically increment word count atomic_add(&global_hash_table[index]->count,1); goto end0; } } while(global_hash_table[++index]); //not in the table use next free index (if we can) void *prev=global_hash_table[index]; int test=atomic_compare_exchange_n(global_hash_table+index,&prev,word); if(test){ uint64_t old_indices_index=atomic_fetch_add(&indices_index,1); hash_table_indices[old_indices_index]=index; goto end1; } //if !test the compare exchange failed and we need to keep looping } end0: return 0; end1: return 1; }
UTYPE SIZE(libat_load) (UTYPE *mptr, int smodel) { UTYPE t = 0; if (maybe_specialcase_relaxed(smodel)) atomic_compare_exchange_n (mptr, &t, 0, true, __ATOMIC_RELAXED, __ATOMIC_RELAXED); else if (maybe_specialcase_acqrel(smodel)) atomic_compare_exchange_n (mptr, &t, 0, true, __ATOMIC_ACQ_REL, __ATOMIC_ACQ_REL); else atomic_compare_exchange_n (mptr, &t, 0, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return t; }
void SIZE(libat_store) (UTYPE *mptr, UTYPE newval, int smodel) { UTYPE oldval; pre_barrier (smodel); oldval = *mptr; while (!atomic_compare_exchange_n (mptr, &oldval, newval, true, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) continue; post_barrier (smodel); }
UTYPE SIZE(C3(libat_,NAME,_fetch)) (UTYPE *mptr, UTYPE opval, int smodel) { UTYPE oldval, t; pre_barrier (smodel); oldval = *mptr; do { t = OP(oldval, opval); } while (!atomic_compare_exchange_n (mptr, &oldval, t, true, __ATOMIC_RELAXED, __ATOMIC_RELAXED)); post_barrier (smodel); return t; }