read/write
```
pwb_write_internal():写
|__ assert(tx->mode == MTM_MODE_pwbnl || tx->mode == MTM_MODE_pwbetl) //检查模式
|__ if(tx->satus == TX_ACTIVE) {assert(0)} //检察事务的状态是否为TX_ACTIVE
|__ if(((uintptr_t) addr >= PSEGMENT_RESERVED_REGION_START && (uintptr_t) addr < (PSEGMENT_RESERVED_REGION_START + PSEGMENT_RESERVED_REGION_SIZE))) //过 滤掉易失性内存的访问
|__ access_is_nonvolatile = 1
|__ if(enable_isolation)
|__ lock = GET_LOCK(addr)
|__ if(LOCK_GET_OWNED(1))
|__ if (modedata->w_set.entries <= write_set_head && write_set_head < modedata->w_set.entries + modedata->w_set.nb_entries) //判断write_set_head是否落入写集之内
|__ w_entry_t* matching_entry = matching_write_set_entry(write_set_head. addr, &write_set_tail, &last_entry_in_same_cache_block)
if(matching_entry != NULL) //之前有写入过相同的地址
|__ if(matching_entry->mask !=0) //如果掩码不为0
|__ mask_new_value(matching_entry, addr, value, mask) //覆盖并返回新的值
|__ if(access_is_nonvolatile) //如果访问是非易失的
|__ M_TMLOG_WRITE() //写入日志
|__ return matching_entry //返回该条目
|__ else //没有找到匹配的条目,即之前没有写入过相同的地址
|__ if(modedata->w_set.nb_entries == modedata->w_set_size) //如果写集的条目数与写集的大小相等
|__ modedata->w_set.size *= 2 //扩展写集
|__ modedata->w_set_reallocate = 1 //重新调整大小
|__ mtm_pwb_reasart_transaction(tx, RESTART_REALLOCATE) // 重启事务,REATART_REALLOCATE是重启事务的原因
|__ rollback_transaction(tx) //回滚事务
|__ cm_delay(tx) //等待竞争的锁被释放
|__ pwb_prepare_transaction(tx) //准备开始事务,主要是初始化一些事,将读集和写集全部设为空,,并开始事务日志
|__ _ITM_siglongjmp(tx->jb, actions) //解析缓冲区,并跳到合适的例程
|__ else //如果没有找到匹配的条目且如果写集条目与写集的大小不相等,则构建新的条目
|__ w=&modedata->w_set.entries[modedata->w_set.nb_entries] //新的条目连接在已存在的写集条目之后,其在写集条目之后数组的小标自然就是写集条目的总数,即w_set.nb_entries
|__ version = wite_set_tail -> version //从之前的写集中获取版本(链表中的所有条目具有相同的版本)
|__ w_entry_t* initialized_entry = initialize_write_set_entry(w, addr, value, mask,version, lock, access_is_nonvolatile) //初始化写集条目
|__ insert_write_set_entry_after(initialized_entry, write_set_tail, tx, last_entry_in_same_cache_block) //将新的条目插入到写集末尾
|__ return initialized_entry //返回该条目
|__ else //如果该区域没有被该线程锁住,在读之后再处理写
|__ if(enable_isolation)
|__ version = LOCK_GET_TIMESTAMP(1) //获取版本号,检查时间戳
|__ if(version>modedata->end)) //如果版本比最后一个版本都要新,说明我们在之前可能读到了旧版本
|__ if(!tx->can_extend || mtm_has_read(tx, modedata, lock) != NULL) //首先考虑扩展
|__ cm_visible_read(tx) //利用可见读来退出
|__ mtm_pwb_restart_transaction(tx, RESTART_VALIDATE_WRITE) //重启事务,重启的原因是RESTART_VALIDATE_WRITE
|__ if(modedata->w_set.nb_entries == modedata->w_set.size)
. 。。。。。。。。。。。。。。。。。
pwb_load_internal():读
|__ assert(tx->mode == MTM_MODE_pwbnl || tx->mode == MTM_MODE_pwbetl) //检查模式
|__ assert(tx->status == TX_ACTIVE)
|__ if(((uintptr_t) addr >= PSEGMENT_RESERVED_REGION_START && (uintptr_t) addr < (PSEGMENT_RESERVED_REGION_START + PSEGMENT_RESERVED_REGION_SIZE))) //过滤掉易失性内存的访问
|__ if(enable_isolation) //检查竞争管理是否升级到写锁
|__ if(cm_upgrade_lock(tx)) //如果升级到写锁
|__ w = pwb_write_internal() //写入
|__ if(enable_isolation)
|__ lock = GET_LOCK(addr) //get reference to lock
//检查重复读并从读集中获取值
|__ if(LOCK_GET_OWNED(1))
|__ w=(w_entry_t *)LOCK_GET_ADDR(1)
|__ if(modedata->w_set.entries <= w && w<modedata-> w_set.entries+ modedata->w_set.nb_entries) //检查地址是否落入到写集中
|__ while(1) //如果地址是落到写集之内,那么就从写集中获取值,while循环遍历写集
|__ if(addr == w_addr) //判断之前有读过相同地址,
|__ value = (w-mask==0 ? ATOMIC_LOAD(addr) : w-value) //如果之前有读过相同地址,那么就判断w->mask是否为0,如果为0则从内存中获取值,不为0 就直接返回w中该地址指向的值
|__ break //已经读到了值,直接跳出循环
|__ if(w->next==NULL) //如果之前没有读过相同地址,判断要读的条目是写集中的最后一个条目
|__ value=ATOMIC_LOAD(addr) //如果之前没有读过相同地址,那么就直接从内存中获取值
|__ break跳出循环 //写集遍历完毕,跳出循环
|__ w=w->next //如果前面两个条件都不满足,则一直遍历写集(指向下一个条目)
|__ return value //返回读到的值
|__ value = ATOMIC_LOAD_ACQ(addr) //如果没有锁住,则从。。。中加载值
|__ if(enable_isolation)
|__ l2=ATOMIC_LOAD_ACQ(lock)
if (l != l2) {
l = l2;
goto restart_no_load; //回到if(LOCK_GET_OWNED(1))
}
|__ version= LOCK_GET_TIMESTAMP(1) //获取时间戳
|__ if(version > modedata->end) //检查时间戳是否是有效的,无效的话说明我们之前可能读到了旧版本,首先考虑扩展
|__ if(!tx->can_extend || 1pwb_extend(tx, modedata)) //如果不能扩展,则直接退出
|__ cm_visible_read(tx) //利用可见读来退出
|__ mtm_pwb_restart_transaction(tx, RESTART_VALIDATE_WRITE) //重启事务,重启的原因是RESTART_VALIDATE_WRITE
读取前后都判断版本号,确保读取过程中和数据没有改变
|__ l = ATOMIC_LOAD_ACQ(lock);
if (l != l2) {
l = l2;
goto restart_no_load; // 回到if(LOCK_GET_OWNED(1))
}
|__ 如果上条件不满足,即版本是有效的,则进行以下步骤:更新事务,将地址和版本更新到读集,并返回读到的值
|__ if(enable_isolation)
|__ if (modedata->r_set.nb_entries == modedata->r_set.size) //如果读集已满,则先尝试扩展
|__ mtm_allocate_rs_entries(tx, modedata, 1) //重新调整读集的大小
|__ r = &modedata->r_set.entries[modedata->r_set.nb_entries++]
|__ r->version = version
|__ r->lock = lock //生成读集记录,初始化数据版本和锁指针
|__ return value //返回读到的值