uint64_t Descriptor::CondCAS()

in src/mwcas/mwcas.cc [414:453]


uint64_t Descriptor::CondCAS(uint32_t word_index, uint64_t dirty_flag) {
  auto* w = &words_[word_index];
  uint64_t cond_descptr = SetFlags((uint64_t)w, kCondCASFlag);

retry:
  uint64_t ret = CompareExchange64(w->address_, cond_descptr, w->old_value_);
  if(IsCondCASDescriptorPtr(ret)) {
    // Already a CondCAS descriptor (ie a WordDescriptor pointer)
    WordDescriptor* wd = (WordDescriptor*)CleanPtr(ret);
    RAW_CHECK(wd->address_ == w->address_, "wrong address");
    uint64_t dptr = SetFlags(wd->GetDescriptor(), kMwCASFlag | dirty_flag);
    uint64_t desired =
      *wd->status_address_ == kStatusUndecided ? dptr : wd->old_value_;

    if(*(volatile uint64_t*)wd->address_ != ret) {
      goto retry;
    }
    auto rval = CompareExchange64(
      wd->address_,
      *wd->status_address_ == kStatusUndecided ? dptr : wd->old_value_,
      ret);
    if(rval == ret) {
      if(desired == dptr) {
        // Another competing operation succeeded, return
        return dptr;
      }
    }

    // Retry this operation
    goto retry;
  } else if(ret == w->old_value_) {
    uint64_t mwcas_descptr = SetFlags(this, kMwCASFlag | dirty_flag);
    CompareExchange64(w->address_,
        status_ == kStatusUndecided ? mwcas_descptr : w->old_value_,
        cond_descptr);
  }

  // ret could be a normal value or a pointer to a MwCAS descriptor
  return ret;
}