当前位置: 首页 > 工具软件 > Mnemosyne > 使用案例 >

mnemosyne 读写模块源码分析

西门淮晨
2023-12-01

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                                                      //返回读到的值
 类似资料: